概述
數組和鏈表都是最基礎的線性數據結構,可以用來實現棧,隊列等非線性,有特定應用場景的數據結構,我們發現數組作為數據存儲結構有很很多缺陷,在無序數組中搜索效率低,在有序數組中插入效率又很低,無論哪種情況刪除操作效率都很低;而且數組一旦創建,大小不可更改。
本文我們介紹一種新的數據儲存結構,鏈表,除非是要頻繁通過下標訪問數據,否則在很多場合都可以用鏈表替換數組;
1鏈表組成結構
鏈表通常由一連串節點組成,每個節點包含該節點的數據和指向上一節點或者下一節點的引用(鏈接)
2 單向鏈表
單向鏈表是最簡單的鏈表,單鏈表節點包含兩部分內容,一是保存某些數據信息的對象,另一個是存儲下一個節點的地址,最后一個節點存儲的地址是指向空值;
單向鏈表只可向一個方向遍歷,一般查找一個節點的時候需要從第一個節點開始每次訪問下一個節點,一直訪問到需要的位置。而插入一個節點,對於單向鏈表,我們只提供在鏈表頭插入,只需要將當前插入的節點設置為頭節點,next指向原頭節點即可。刪除一個節點,我們將該節點的上一個節點的next指向該節點的下一個節點。
在鏈表頭增加新節點 :
刪除節點:
代碼演示:
package datastrunture.link; public class SingleLinkList { private int size; private Node head; public SingleLinkList() { this.size = 0; this.head = null; } /** * 鏈表每個節點類 */ private class Node{ private Object data; private Node next; public Node(Object data){ this.data=data; } } //在鏈表頭添加節點 public void addHead(Object data){ Node newHead = new Node(data); if(size==0){ head = newHead; }else{ newHead.next = head; head = newHead; } size++; } //刪除鏈表頭的元素 public Object deleteHead() { if (size > 0) { Object data = head.data; head = head.next; size--; return data; } return null; } //查找指定元素,找到返回節點Node public Node find(Object obj){ Node current = head; int tempSize = size; while(tempSize>0){ if(obj.equals(current.data)){ return current; }else{ current = current.next; } tempSize--; } return null; } //刪除指定元素 public boolean delete(Object value){ if(size==0){ return false; } Node current = head; Node pre = head; while (current.data!=value){ if(current.next==null){ return false; }else { pre = current; current = current.next; } } if(current == head){ head = current.next; size--; }else { pre.next = current.next; size--; } return true; } //判斷是否為空 public boolean isEmpty(){ return (size==0); } //遍歷鏈表 public void display(){ if(size>0){ Node node = head; int tempSize = size; if(tempSize ==1){ System.out.print( "["+node.data+"]"); } while(tempSize>0){ if(node.equals(head)){ System.out.print("["+node.data+"->"); }else if(node.next == null){ System.out.print(node.data+"]"); }else{ System.out.print(node.data+"->"); } node = node.next; tempSize--; } System.out.println(); }else{ System.out.println("[]"); } } }
3 雙端鏈表:
對於單項鏈表,我們如果想在尾部添加一個節點,那么必須從頭部一直遍歷到尾部,找到尾節點,然后在尾節點后面插入一個節點。這樣操作很麻煩,如果我們在設計鏈表的時候多個對尾節點的引用,那么會簡單很多。
代碼演示:
package datastrunture.link; public class DoublePointLinkedList { private Node head;//頭節點 private Node tail;//尾節點 private int size;//節點的個數 private class Node{ private Object data; private Node next; public Node(Object data){ this.data = data; } } public DoublePointLinkedList(){ size = 0; head = null; tail = null; } //鏈表頭新增節點 public void addHead(Object data){ Node node = new Node(data); if(size == 0){//如果鏈表為空,那么頭節點和尾節點都是該新增節點 head = node; tail = node; }else{ node.next = head; head = node; } size++; } //鏈表尾新增節點 public void addTail(Object data){ Node node = new Node(data); if(size == 0){//如果鏈表為空,那么頭節點和尾節點都是該新增節點 head = node; tail = node; }else{ tail.next = node; tail = node; } size++; } //刪除頭部節點,成功返回true,失敗返回false public boolean deleteHead(){ if(size == 0){//當前鏈表節點數為0 return false; } if(head.next == null){//當前鏈表節點數為1 head = null; tail = null; }else{ head = head.next; } size--; return true; } //判斷是否為空 public boolean isEmpty(){ return (size ==0); } //獲得鏈表的節點個數 public int getSize(){ return size; } //顯示節點信息 public void display(){ if(size >0){ Node node = head; int tempSize = size; if(tempSize == 1){//當前鏈表只有一個節點 System.out.println("["+node.data+"]"); return; } while(tempSize>0){ if(node.equals(head)){ System.out.print("["+node.data+"->"); }else if(node.next == null){ System.out.print(node.data+"]"); }else{ System.out.print(node.data+"->"); } node = node.next; tempSize--; } System.out.println(); }else{//如果鏈表一個節點都沒有,直接打印[] System.out.println("[]"); } } }
4 雙向鏈表
package datastrunture.link; public class DoubleLinkedList { private Node head;//表示鏈表頭 private Node tail;//表示鏈表尾 private int size;//表示鏈表的節點個數 private class Node{ private Object data; private Node next; private Node prev; public Node(Object data){ this.data = data; } } public DoubleLinkedList(){ size = 0; head = null; tail = null; } //在鏈表頭增加節點 public void addHead(Object value){ Node newNode = new Node(value); if(size == 0){ head = newNode; tail = newNode; }else{ head.prev = newNode; newNode.next = head; head = newNode; } size++; } //在鏈表尾增加節點 public void addTail(Object value){ Node newNode = new Node(value); if(size == 0){ head = newNode; tail = newNode; }else{ newNode.prev = tail; tail.next = newNode; tail = newNode; } size++; } //刪除鏈表頭 public Node deleteHead(){ Node temp = head; if(size != 0){ head = head.next; head.prev = null; size--; } return temp; } //刪除鏈表尾 public Node deleteTail(){ Node temp = tail; if(size != 0){ tail = tail.prev; tail.next = null; size--; } return temp; } //獲得鏈表的節點個數 public int getSize(){ return size; } //判斷鏈表是否為空 public boolean isEmpty(){ return (size == 0); } //顯示節點信息 public void display(){ if(size >0){ Node node = head; int tempSize = size; if(tempSize == 1){//當前鏈表只有一個節點 System.out.println("["+node.data+"]"); return; } while(tempSize>0){ if(node.equals(head)){ System.out.print("["+node.data+"->"); }else if(node.next == null){ System.out.print(node.data+"]"); }else{ System.out.print(node.data+"->"); } node = node.next; tempSize--; } System.out.println(); }else{//如果鏈表一個節點都沒有,直接打印[] System.out.println("[]"); } } }