前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java链表的基本使用

Java链表的基本使用

作者头像
全栈程序员站长
发布2022-08-18 21:29:10
4720
发布2022-08-18 21:29:10
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

链表是一种根据元素节点逻辑关系排列起来的一种数据结构。利用链表可以保存多个数据,这一点类似于数组的概念,但是数组本身有一个缺点—— 数组的长度固定,不可改变,在长度固定的情况下首选的肯定是数组,但是在现实的开发之中往往要保存的内容长度是不确定的,那么此时就可以利用链表这样的结构来代替数组的使用。

链表是一种最为简单的数据结构,它的主要目的是依靠引用关系来实现多个数据的保存。

下面是定义一个简单的类用来保存节点关系,并将所有节点链接起来。

例子1:

代码语言:javascript
复制
//每一个链表实际上就是由多个节点组成的
class Node { 
       
	private String data; //用于保存数据
	private Node next;   //用于保存下一个节点
	
	public Node(String data){ 
     //每一个Node类对象都必须保存有数据
		  this.data = data ;
	}
	
	public void setNext(Node next){ 
   
		  this.next = next ;
	}
	
	public Node getNext(){ 
   
		  return this.next ;
	}
	
	public String getData(){ 
   
		  return this.data ;
	}
}

public class LinkedList { 
   
	 
	public static void main(String[] args) { 
   
		
		//第一步:准备数据
		Node root = new Node("火车头") ;
		Node n1 = new Node("车厢A") ;
		Node n2 = new Node("车厢B") ;

		// 链接节点
		root.setNext(n1);
		n1.setNext(n2);
		
		//第二步:取出所有数据
		Node currentNode = root ;  //从当前根节点开始读取
		while( currentNode !=  null){ 
   
			System.out.println(currentNode.getData()) ;
			//将下一个节点设置为当前节点s
			currentNode = currentNode.getNext() ;
		}
 }
}

运行:

代码语言:javascript
复制
火车头
车厢A
车厢B

例子2: 在进行链表操作的时候,首先需要的是一个根节点(第一个节点即为根节点),之后每一个节点的引用都保存在上一节点的next属性之中,而在进行输出的时候也应该按照节点的先后顺序,一个一个取得每一个节点所包装的数据。

代码语言:javascript
复制
public class LinkedList { 
   

	public static void main(String[] args) { 
   
	 Link link = new Link() ;
	 link.add("hello");   //增加节点
	 link.add("world");
	 link.add("wwww");
	 link.print();     //打印数据 
	}	
}

//每一个链表实际上就是由多个节点组成的
class Node { 
    
	private String data; // 用于保存数据
	private Node next; // 用于保存下一个节点
	
	public Node(String data) { 
     // 每一个Node类对象都必须保存有响应的数据
		this.data = data;
	}

	public void setNext(Node next) { 
   
		this.next = next;
	}

	public Node getNext() { 
   
		return this.next;
	}

	public String getData() { 
   
		return this.data;
	}

	// 实现节点的添加:
	// 第一次调用(Link):this代表Link.root
	// 第二次调用(Node):this代表Link.root.next
	// 第三次调用(Node):this代表Link.root.next.next
	public void addNode(Node oldNode,Node newNode) { 
   	
		System.out.println("now:"+oldNode);
		if (this.next == null) { 
      // 保存新节点
			this.next = newNode; 
		} else { 
                    // 当前节点后面还有节点 
			this.next.addNode(this.next,newNode);  // 当前节点的下一个节点继续保存,这里采用的是递归添加节点
		}
		System.out.println(oldNode+"=>"+this.next);
	}

	// 第一次调用(Link):this代表Link.root
	// 第二次调用(Node):this代表Link.root.next
	// 第三次调用(Node):this代表Link.root.next.next
	public void printNode() { 
   
		System.out.println("pp:"+this.data);// 输出当前数据
		if (this.next != null) { 
         // 如果还有下一个节点,输出下一节点
			this.next.printNode();   // 递归打印节点,注意这里的this.next中的this指代
		}
	}
}


// 链表增加节点,输出节点数据
class Link { 
   
	
	private Node root; //新建根节点

	public void add (String data){ 
   
		  Node newNode = new Node(data);  //链表中新增节点类对象 
		  if(this.root == null ){ 
            // 如果链表还没有任何节点,就添加第一个节点作为根节点
			  this.root = newNode;   
			  System.out.println("root:"+this.root);
		  }else{ 
    
			  System.out.println("new:"+newNode);
			  this.root.addNode(this.root,newNode);  //从根节点节点新链接一个节点
		  }
	}
	
	//输出当前节点数据
	public void print(){ 
   
		  if( this.root != null ){ 
     
			  this.root.printNode();
		  }
	}

}

运行:

代码语言:javascript
复制
root:test.Node@7852e922
new:test.Node@4e25154f
now:test.Node@7852e922
test.Node@7852e922=>test.Node@4e25154f
new:test.Node@70dea4e
now:test.Node@7852e922
now:test.Node@4e25154f
test.Node@4e25154f=>test.Node@70dea4e
test.Node@7852e922=>test.Node@4e25154f
pp:hello
pp:world
pp:wwww

例子3:

关键是构造一个类,里面包含一个指向下一个元素的对象(指向下一个元素的指针)

代码语言:javascript
复制
public class LinkedList{ 
   
	
	public static void main(String[] args){ 
   

        MyLinkedList linkedList = new MyLinkedList();
        System.out.println("-------start-------");
        System.out.println("ll:"+linkedList.listEm());
        
        for (int i=0;i<5;i++){ 
      //新建链表
            linkedList.add(i+1);
        }
        System.out.println("mm:"+linkedList.listEm());  //打印链表
        
        for(int i=0;i<5;i++){ 
     //删除链表
            System.out.println("remove:"+linkedList.remove());
        }

        System.out.println("kk:"+linkedList.listEm());
        System.out.println("-------end-------");
    }
}

class Node<T> { 
   
    Node<T> next;
    T element;
    public Node( Node<T> next, T element){ 
   
        this.next = next;
        this.element = element;
    }
}


class MyLinkedList<T> { 
   
	
	private int size ;	
    Node<T> last;     //指向list中最后一个元素 
    Node<T> first;    //指向list中第一个元素 
    Node<T> currRead; //指向当前读取的元素 
 
    // 默认构造函数
    public MyLinkedList(){ 
      
        this.size = 0;
        this.last =  new Node(null,-1);
        this.first = last;
        this.currRead = first;
    }

    
    //往链表中添加数据(队尾添加数据) 
    public void add(T element){ 
   
        Node<T> newNode = new Node<T>(null,element);
        this.last.next = newNode;
        this.last = newNode;  // 引用平移
        if(size == 0){ 
   
            this.first = newNode;
        }
        size ++;
        
    }

    
    //移除链表中的数据(队头移除)
    public T remove(){ 
   
        if(size == 0){ 
   
            System.out.println("empty list ");
            this.currRead = this.first;
            return null;
        }
        T result = this.first.element;
        this.first = this.first.next;
        this.currRead = this.first;
        size--;
        return result;
    }

   //获取队列中的元素
    public T get(){ 
   
        if(this.currRead.next == null){ 
   
            this.setReadAgain();
            return this.currRead.element;
        }
        T result = this.currRead.element;
        this.currRead = this.currRead.next;
        return result;
    }

   //再次从头开始读取数据
    public void setReadAgain() { 
   
        this.currRead = this.first;
    }

    public String listEm(){ 
   
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<size;i++){ 
   
           T ele = this.get();
           sb.append(this.currRead.element + "-->");
        }
        return sb.toString();
    }

    //获取队列大小
    public int getSize(){ 
   
        return this.size;
    }

   
}

运行:

代码语言:javascript
复制
-------start-------
ll:
mm:1-->2-->3-->4-->5-->
remove:1
remove:2
remove:3
remove:4
remove:5
kk:
-------end-------

例四:

代码语言:javascript
复制
public class LinkedList { 
   

public static void main(String [] args){ 
    

	Link l=new Link();  
    mytype[] la;  
    mytype dsome=new mytype("韩敏","dsome",21);  
    mytype shao=new mytype("邵晓","john",45);  
    mytype hua=new mytype("华晓风","jam",46);  
    mytype duo=new mytype("余小风","duo",1000);  
    mytype wang=new mytype("王秋","jack",21);  
    mytype shi=new mytype("韩寒","bob",3000);  
    mytype yu=new mytype("于冬","keven",30); 
	
	l.add(dsome);//测试增加节点 
    l.add(shao);  
    l.add(hua);  
    l.add(wang);  
    l.add(shi);  
    l.add(duo);  
    l.add(yu);  
	
    System.out.println("链表长度:"+l.length());//链表长度
 
    la=l.toArray();  
    for(int i=0;i<la.length;i++){ 
     
		 System.out.println(la[i].getInfo());  
		 }  
    
    System.out.println("是否包含余小风:"+l.contains(duo)+"\n");  
    System.out.println("删除余小风后\n");  
    l.remove(duo);  
    la=l.toArray();  
    for(int i=0;i<la.length;i++){ 
       //转化为数组之后输出 
		 System.out.println(la[i].getInfo());  
	}    
    
	System.out.println("\n利用索引方法输出全部数据");  
    for(int i=0;i<l.length();i++){ 
     
       System.out.println(l.get(i).getInfo());  
    }    
	System.out.println("是否包含余小风:"+l.contains(duo)+"\n");  
	l.clean();  
    System.out.println("执行清空操作后链表长度: "+l.length()+"\t是否为空链表:"+l.isEmpty());  
	}
}




class Link { 
   

	//内部类 
	private class Node{ 
      
		
		private Node next;  
		private mytype data;  
		
		public Node(mytype data){ 
     
		      this.data=data;  
		 }  
		
		public void addNode(Node newNode){ 
     //增加节点 
		      if(this.next==null){ 
     
		        this.next=newNode;   // 指向新的节点
		      }else{ 
     
		        this.next.addNode(newNode);    // 递归调用是为了让next引用指向新的节点
		      }  
		    }  
	
	    public mytype getNode(int index){ 
   //按照角标返回数据 
	
	      if(index==Link.this.foot++){ 
     
	        return this.data;  
	      }else{ 
     
	        return this.next.getNode(index);  
	      }  
	    }  
	
	    public boolean iscontain(mytype data){ 
   //判断是否含有该数据 
	      if(this.data.equals(data)){ 
     
	        return true;  
	      }else{ 
     
	        if(this.next!=null){ 
     
	          return this.next.iscontain(data);  
	        }else{ 
     
	          return false;  
	        }  
	      }  
	    }  
	
	    public void removeNode(Node previous,mytype data){ 
     //删除节点 
	      if(this.data.equals(data)){ 
       //this:下一个节点B
	        previous.next=this.next;    // this.next:节点B的下一个节点C,previous:节点A
	
	      }else{ 
     
	        this.next.removeNode(this,data);  //注意这里的this.next和this的区别:this.next是下一个节点B,this是当前节点A
	      }  
	    }  
	
	
	    public void toArrayNode(){ 
     //转化数组 
	        Link.this.Larray[Link.this.foot ++]=this.data;  //每个节点的数据添加到一个mytype []中
	        if(this.next!=null){ 
     
	          this.next.toArrayNode();  
	        }  
	      }   
}

//内部类定义完毕 
private Node root;  
private int count=0;  
private int foot;  
private mytype [] Larray;

 public void add(mytype data){ 
      //增加节点 
    if(data==null){ 
     
      System.out.print("增加数据失败,数据为空");//测试用 
      return;  
    }  
    
    Node newNode=new Node(data);  //新建节点
    
    if(this.root==null){ 
     
      this.root=newNode;  
      this.count++;  
    }else{ 
     
      this.root.addNode(newNode);  
      this.count++;  
    }  
  }  

  public int length(){ 
   //链表长度 
    return this.count;  
  }  

  public boolean isEmpty(){ 
   //是否为空链表 
    if(this.count==0)return true;  
    else return false;  
  }  

  public void clean(){ 
   //清空链表 
    this.root=null;  
    this.count=0;  
  }  

  public mytype get(int index){ 
   //索引返回节点所存的数据 
        if(index>=this.count||index<0){ 
     
          System.out.print("越界错误");//测试用 
          return null;  
        }else{ 
     
          this.foot=0;  
          return this.root.getNode(index);  
        }  
      }  

   public boolean contains(mytype data){ 
     //判断链表数据是否含data 
        if(data==null)  
          return false;
        else
          return this.root.iscontain(data);  
      }  

    public void remove(mytype data){ 
     //删除指定数据节点 
        if(this.contains(data)){ 
     
	          if(this.root.data.equals(data)){ 
     
	            this.root=this.root.next;  
	            this.count--;     
	          }  
	          else{ 
     
	            this.count--;  
	            this.root.next.removeNode(root,data);  
	          }  
        }else{ 
     
          System.out.print("删除错误");//测试用 
        }  
      }  

      public mytype[] toArray(){ 
     //把链表转化成对象数组 
        if(this.count==0){ 
     
          return null;  
        }  
          this.foot=0;  
          this.Larray=new mytype [this.count];  
          this.root.toArrayNode();  
          return this.Larray;         
      }         
}


class mytype { 
   

	private String name;  
	private String people;  
	private int age;
	
	public mytype(String name,String people,int age){ 
   //链表中的数据(可自定义) 
	    this.name=name;  
	    this.people=people;  
	    this.age=age;  
	  }  
	
    public boolean equals(mytype data){ 
   //判断数据是否相同 
	    if(this==data){ 
     
	      return true;  
	    }  
	    if(data==null){ 
     
	      return false;  
	    }  
	    if(this.name.equals(data.name)&&this.people.equals(data.people)&&this.age==data.age){ 
     
	      return true;  
	    }else{ 
     
	      return false;  
	    }  
	  }
    
	public String getName() { 
   
	    return name;
	}
	
	public void setName(String name) { 
   
	    this.name = name;
	}
	
	public String getPeople() { 
   
	    return people;
	}
	
	public void setPeople(String people) { 
   
	    this.people = people;
	}
	
	public int getAge() { 
   
	    return age;
	}
	
	public void setAge(int age) { 
   
	    this.age = age;
	} 
	
	public String getInfo(){ 
     
	    return "名字 :"+this.name+"\n"+  
	       "人物 :"+this.people+"\n"+  
	       "年龄 :"+this.age;  
	  }     
}

运行:

代码语言:javascript
复制
链表长度:7
名字 :韩敏
人物 :dsome
年龄 :21
名字 :邵晓
人物 :john
年龄 :45
名字 :华晓风
人物 :jam
年龄 :46
名字 :王秋
人物 :jack
年龄 :21
名字 :韩寒
人物 :bob
年龄 :3000
名字 :余小风
人物 :duo
年龄 :1000
名字 :于冬
人物 :keven
年龄 :30
是否包含余小风:true

删除多余后

名字 :韩敏
人物 :dsome
年龄 :21
名字 :邵晓
人物 :john
年龄 :45
名字 :华晓风
人物 :jam
年龄 :46
名字 :王秋
人物 :jack
年龄 :21
名字 :韩寒
人物 :bob
年龄 :3000
名字 :于冬
人物 :keven
年龄 :30

利用索引方法输出全部数据
名字 :韩敏
人物 :dsome
年龄 :21
名字 :邵晓
人物 :john
年龄 :45
名字 :华晓风
人物 :jam
年龄 :46
名字 :王秋
人物 :jack
年龄 :21
名字 :韩寒
人物 :bob
年龄 :3000
名字 :于冬
人物 :keven
年龄 :30
是否包含多余:false

执行清空操作后链表长度: 0	是否为空链表:true

参考: https://blog.csdn.net/qq_37199582/article/details/79244657 https://blog.csdn.net/google_huchun/article/details/52824024

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/135767.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月3,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档