內容概括:
鏈表像火車一樣,每個節點相當於一節車廂,每一節車廂存放真正的數據,每一節車廂之間要有next鏈接
組成鏈表的內部節點和next類:
public class LinkedList<E> { //私有內部類 private class Node {//只有在鏈表內才能訪問 public E e;//節點數據 public Node next;//節點next public Node(E e, Node next) { this.e = e;//用戶傳進來的e賦值給當前節點的e this.next = next;//用戶傳來的next當前節點的next } public Node(E e) { this(e, null); } public Node() { this(null, null) } @Override public String toString(){ return e.toString();} } private Node head;//鏈表頭 private int size;//鏈表長度 public LinkedList(){ head=null; size=0; } //獲取鏈表中元素的個數 public int getSize(){ return size; } //返回鏈表是否爲空 public boolean isEmpty(){ return size==0; } }
//在鏈表頭添加新的元素 public void addFirst(E e){ // Node node=new Node(); //// node.next=head; //// head=node; head=new Node(e,head);//當前節點爲用戶傳進來的節點,當前節點的next爲用戶上一個頭結點 size++; }
如果順序調換。
//在鏈表的index(0-based)位置添加新的元素e //在鏈表中不是一個常用操作,練習用: public void add(int index,E e){ if(index<0||index>size){//判斷index的合法性 throw new IllegalArgumentException("Add is Fail,Illega Index"); } if(index==0) addFirst(e); else{ Node prev=head; for (int i=0;i<index-1;i++){//讓prev找到index-1位置 prev=prev.next;//讓prev挪向待插入位置的前一個節點 // Node node =new Node(e);//1 // node.next=prev.next;//2 // prev.next=node;//3 //new Node(e,prev.next);完成前兩句話的任務 //prev.next=..完成第三句話的任務 prev.next=new Node(e,prev.next); size++; }}} //在鏈表的末尾添加新的元素e public void addLast(E e){ add(size,e); }
元素從0開始,dummyHead是0位置的前一個節點
public LinkedList(){ dummyHead=new Node(null,null);//創建一個虛擬頭結點 size=0; } //獲取鏈表中元素的個數 public int getSize(){ return size; } //返回鏈表是否爲空 public boolean isEmpty(){ return size==0; } //在鏈表的index(0-based)位置添加新的元素e //在鏈表中不是一個常用操作,練習用: public void add(int index,E e){ if(index<0||index>size){//判斷index的合法性 throw new IllegalArgumentException("Add is Fail,Illega Index"); } Node prev=dummyHead;//虛擬頭結點,0位置的元素的前一個節點 for (int i=0;i<index;i++)//讓prev找到index位置的前一個位置 prev=prev.next;//讓prev挪向待插入位置的前一個節點 prev.next=new Node(e,prev.next); size++; } //在鏈表頭添加新的元素 public void addFirst(E e){ add(0,e); } //在鏈表的末尾添加新的元素e public void addLast(E e){ add(size,e); }
獲得鏈表的第index個元素
//獲得鏈表的第index(0-based)個位置的元素 public E get(int index){ //判斷index的合法性 if(index<0||index>size){//判斷index的合法性 throw new IllegalArgumentException("Get is Fail,Illega Index"); } Node cur=dummyHead.next;//從dummyHead的下一個節點開始遍歷 for(int i=0;i<index;i++) cur=cur.next; return cur.e;//返回的就是index位置的元素 } //獲得鏈表的第一個元素 public E getFirst(){ return get(0); } //獲得鏈表的最後一個元素 public E getLast(){ return get(size-1);//從0開始算的 0個位置有一個元素 size=1 }
修改index位置的元素
//修改鏈表的第index(0-based)個位置的元素 public void set(int index,E e){ //判斷index的合法性 if(index<0||index>size){//判斷index的合法性 throw new IllegalArgumentException("Set is Fail,Illega Index"); } Node cur=dummyHead.next; for (int i=0;i<index;i++) cur=cur.next; cur.e=e;//讓第index位置的e變成新的額 }
查找鏈表有無此元素
//查找鏈表是否有元素e public boolean contains(E e) { Node cur = dummyHead.next; while (cur != null) {//沒到末尾 if (cur.e.equals(e))// return true; cur = cur.next;//否則繼續往下找 } return false;//找不到 } @Override public String toString(){ StringBuilder res=new StringBuilder(); Node cur=dummyHead.next; // for(Node cur=dummyHead.next;cur!=null;cur=cur.next)等價 while(cur!=null){ res.append(cur+"->"); cur=cur.next; } res.append("NULL");//到達節尾 return res.toString(); }
Main_Activity.java中實現
public class Main { public static void main(String[] args) { LinkedList<Integer> linkedList=new LinkedList<>(); for(int i=0;i<5;i++){ linkedList.addFirst(i); System.out.println(linkedList); } linkedList.add(2,666);//在索引爲2的位置添加元素666 System.out.println(linkedList); } }
結果
0->NULL 1->0->NULL 2->1->0->NULL 3->2->1->0->NULL 4->3->2->1->0->NULL 4->3->666->2->1->0->NULL
鏈表刪除操作的實現:
//從鏈表中刪除index元素的草(0-based) public E remove(int index){ //判斷index的合法性 if(index<0||index>size){//判斷index的合法性 throw new IllegalArgumentException("Set is Fail,Illega Index"); } Node prev=dummyHead; for (int i=0;i<index;i++){ prev=prev.next;//存待刪除之前的節點 } Node retNode=prev.next;//要刪除的節點retNode prev.next=retNode.next;//跳過retNode retNode=null; size--; return retNode.e;//返回刪除的的元素 } //刪除第一個元素 public E removeFirst(){ return remove(0); } //刪除最後一個元素 public E removeLast(){ return remove(size-1); }
Main實現
public class Main { public static void main(String[] args) { LinkedList<Integer> linkedList=new LinkedList<>(); for(int i=0;i<5;i++){ linkedList.addFirst(i); System.out.println(linkedList); } linkedList.add(2,666);//在索引爲2的位置添加元素666 System.out.println(linkedList); //刪除2的元素 linkedList.remove(2); System.out.println(linkedList); //刪除第一個元素 linkedList.removeFirst(); System.out.println(linkedList); //刪除最後的元素 linkedList.removeLast(); System.out.println(linkedList); } }
結果
0->NULL 1->0->NULL 2->1->0->NULL 3->2->1->0->NULL 4->3->2->1->0->NULL 4->3->666->2->1->0->NULL 4->3->2->1->0->NULL 3->2->1->0->NULL 3->2->1->NULL
添加操作:O(n)
刪除操作:O(n)
修改操作:O(n)
查找操作: O(n)
要想實現上一節只對鏈表頭進行操作,可以將鏈表實現棧,將鏈表頭看做棧頂
public interface Stack<E> { int getSize();//返回棧的元素個數 boolean isEmpty();//返回棧是否爲空 void push(E e);//入棧 E pop();//出棧 E peek();//查看棧末尾的元素 }
public class LinkedListStack<E> implements Stack<E>{ private LinkedList<E> list; public LinkedListStack(){ list=new LinkedList<>(); } @Override public int getSize(){ return list.getSize(); } @Override public boolean isEmpty(){ return list.isEmpty(); } //給棧頂添加一個元素 @Override public void push(E e){ list.addFirst(e);//鏈表頭是棧頂 } //從棧頂取出元素 @Override public E pop(){ return list.removeFirst(); } //看棧頂的元素 @Override public E peek(){ return list.getFirst(); } @Override public String toString(){ StringBuilder res=new StringBuilder(); res.append("Stack:top "); res.append(list); return res.toString(); } //測試用例 public static void main(String[] args) { LinkedListStack<Integer> stack=new LinkedListStack<>(); for(int i=0;i<5;i++){ stack.push(i);//入棧 System.out.println(stack); } stack.pop();//出棧 System.out.println(stack); } }
結果:
Stack:top 0->NULL Stack:top 1->0->NULL Stack:top 2->1->0->NULL Stack:top 3->2->1->0->NULL Stack:top 4->3->2->1->0->NULL Stack:top 3->2->1->0->NULL
數組棧和鏈表的棧的比較
public class MainTest {//Queue的多態性 //測試使用q運行opCount個enqueue和dequeue操作兩種隊列需要花費的時間,單位秒 private static double testStack(Stack<Integer> stack,int opCount){ long startTime=System.nanoTime();//計算當時時間,單位納秒 //。。。。。你要進行的操作 //生成隨機數 Random random=new Random(); for(int i=0;i<opCount;i++){ //入隊插入隨機數 stack.push(random.nextInt(Integer.MAX_VALUE));//0-Integer最大值 } for(int i=0;i<opCount;i++){ //出隊操作 stack.pop(); } long endTime=System.nanoTime();//計算結束時間,單位納秒 return (endTime-startTime)/1000000000.0;//轉換單位成秒 } public static void main(String[] args) { int opCount=100000; //數組棧的操作 ArrayStack<Integer> arrayStack=new ArrayStack<>(); double time1=testStack(arrayStack,opCount); System.out.println("ArrayStack Time="+time1+"s"); //鏈表實現的棧的操作 LinkedListStack<Integer> linkedListStack=new LinkedListStack<>(); double time2=testStack(linkedListStack,opCount); System.out.println("LinkedListStack Time="+time2+"s"); } }
結果:並不是所有情況LinkedListStack都比ArrayStack時間快
ArrayStack Time=0.037542493s LinkedListStack Time=0.021257096s
在隊尾中添加一個tail屬性,來控制元素的入隊操作,時間複雜度爲O(1)
head屬性來控制出隊操作,時間複雜度也爲O(1)
基本屬性
public class LinkedListQueue<E> implements Queue<E> { //私有內部類 private class Node {//只有在鏈表內才能訪問 public E e;//節點數據 public Node next;//節點next public Node(E e, Node next) { this.e = e;//用戶傳進來的e賦值給當前節點的e this.next = next;//用戶傳來的next當前節點的next } public Node(E e) { this(e, null); } public Node() { this(null, null); } @Override public String toString() { return e.toString(); }} private Node head, tail;//頭尾節點 private int size; public LinkedListQueue() { head = null; tail = null; size = 0; } @Override public int getSize() { return size; } @Override public boolean isEmpty() { return size == 0; }}
進隊操作
//進隊操作、在隊尾中插入元素 @Override public void enqueue(E e){ if (tail == null) {//鏈表尾如爲空,則隊首head也爲空 tail = new Node(e); head = tail; } else { tail.next = new Node(e); tail = tail.next; } size++; }
出隊操作
//出隊操作,從隊首 @Override public E dequeue(){ if(isEmpty()) throw new IllegalArgumentException("Cannot dequeue from an Empty queue"); Node reNode=head; head=head.next; reNode.next=null; if(head==null) tail=null; size--; return reNode.e; } //獲取隊首元素 @Override public E getFront(){ if(isEmpty()) throw new IllegalArgumentException("Queue is empty"); return head.e; }
重寫toString方法
@Override public String toString(){ StringBuilder res=new StringBuilder(); res.append("Queue:front "); Node cur=head; while (cur!=null){ res.append(cur+"->"); cur=cur.next; } res.append("NULL tail"); return res.toString(); }
測試方法:
public static void main(String[] arg){ LinkedListQueue<Integer> queue=new LinkedListQueue<>(); for(int i=0;i<10;i++){ queue.enqueue(i); System.out.println(queue); //每插入隊列3個元素,取出一個元素 if(i%3==2){//0、1、2 2對3取餘爲2 queue.dequeue(); System.out.println(queue); } } }
結果:
Queue:front 0->NULL tail Queue:front 0->1->NULL tail Queue:front 0->1->2->NULL tail Queue:front 1->2->NULL tail Queue:front 1->2->3->NULL tail Queue:front 1->2->3->4->NULL tail Queue:front 1->2->3->4->5->NULL tail Queue:front 2->3->4->5->NULL tail Queue:front 2->3->4->5->6->NULL tail Queue:front 2->3->4->5->6->7->NULL tail Queue:front 2->3->4->5->6->7->8->NULL tail Queue:front 3->4->5->6->7->8->NULL tail Queue:front 3->4->5->6->7->8->9->NULL tail