咱們知道,數組做爲數據存儲結構有必定的缺陷。在無序數組中,搜索時低效的;而在有序數組中,插入效率又很低;無論在哪種數組中刪除效率都很低。何況一個數組建立後,它的大小是沒法改變的。而鏈表多是繼數組以後第二種使用得最普遍的通用數據結構了。這裏主要來討論並寫一個單鏈表和雙向鏈表。數組
顧名思義,單鏈表只能從表頭到表尾的順序,每一個節點中保存了指向下一個節點的指針;雙向鏈表則能夠反向遍歷,由於節點中既保存了向後節點的指針,又保存了向前節點的指針。因爲鏈表結構相對簡單,這裏再也不贅述,直接經過程序來查看它們常見的操做:數據結構
public class Link { public int data; public Link next; public Link(int data) { this.data = data; next = null; } public void displayLink() { System.out.print("[ " + data + " ]"); } }
public class LinkedList { //頭節點 private Link first; //鏈表中節點數量 private int nElem; //添加頭結點 public void insertFirst(int value) { Link newLink = new Link(value); // newLink --> old first newLink.next = first; // first --> newLink first = newLink; nElem++; } //刪除頭結點 public Link deleteFirst() { if (isEmpty()) { System.out.println("The Link is empty!"); return null; } Link temp = first; first = first.next; nElem--; return temp; } /* 下面是有序鏈表的插入 * 這樣簡單排序就能夠用鏈表來實現,複雜度爲O(n) * 定義一個方法,傳入一個數組 * 在方法內,遍歷數組並調用insert方法就能夠將數組中的數據排好序*/ public void insert(int value) { Link newLink = new Link(value); Link current = first; Link previous = null; while (current != null && value > current.data) { previous = current; current = current.next; } if (previous == null) { first = newLink; } else { previous.next = newLink; } newLink.next = current.next; nElem++; } //查找特定節點 public Link find(int value) { Link current = first; while (current.data != value) { if (current.next == null) { return null; } current = current.next; } return current; } //刪除特定節點 public Link delete(int value) { Link current = first; Link previous = first; while (current.data != value) { if (current.next == null) { return null; } previous = current; current = current.next; } if (current == first) { first.next = first; } else { previous.next = current.next; } nElem--; return current; } public void display() { if (isEmpty()) { System.out.println("The link is empty!"); return; } Link current = first; while (current != null) { current.displayLink(); current = current.next; } System.out.println(" "); } public boolean isEmpty() { return (first == null); } public int size() { return nElem; } }
public class Node { public long data; public Node previous; public Node next; public Node(long value) { this.data = value; previous = null; next = null; } public void display() { System.out.print("[" + data + "]"); } }
public class DoublyLinkedList { //頭結點 private Node first; //尾節點 private Node last; private int size; public DoublyLinkedList() { first = null; last = null; size = 0; } //插入頭結點 public void insertFirst(long value) { Node newNode = new Node(value); if (isEmpty()) { first = newNode; } else { // newLink <-- oldFirst.previous first.previous = newNode; // newLink --> first newNode.next = first; } //first --> newLink first = newNode; size++; } //插入尾節點 public void insertLast(long value) { Node newNode = new Node(value); if (isEmpty()) { last = newNode; } else { // newlink <-- oldLast.newxt last.next = newNode; // newLink.previous --> last newNode.previous = last; } last = newNode; size++; } //刪除頭結點 public Node deleteFirst() { Node temp = first; if (isEmpty()) { System.out.println("The link is Empty!"); return null; } //只有一個節點 if (first.next == null) { last = null; } else { first.next.previous = null; } first = first.next; size--; return temp; } //刪除尾節點 public Node deleteLast() { Node temp = last; if (isEmpty()) { System.out.println("The link is empty!"); return null; } //只有一個節點 if (last.previous == null) { first = null; } else { last.previous.next = null; } last = last.previous; size--; return temp; } public boolean insertAfter(long key, long value) { Node current = first; while (current.data != key) { current = current.next; if (current == null) { return false; } } if (current == last) { insertLast(value); } else { Node newNode = new Node(value); newNode.next = current.next; current.next.previous = newNode; newNode.previous = current; current.next = newNode; size++; } return true; } public Node deleteNode(long value) { Node current = first; while (current.data != value) { current = current.next; if (current == null) { return null; } } if (current == first) { deleteFirst(); } else if (current == last) { deleteLast(); } else { current.previous.next = current.next; current.next.previous = current.previous; size--; } return current; } public int size() { return size; } public boolean isEmpty() { return (first == null); } //從頭至尾遍歷鏈表 public void displayForward() { Node current = first; while (current != null) { current.display(); current = current.next; } System.out.println(); } //從未到頭遍歷鏈表 public void displayBackward() { Node current = last; while (current != null) { current.display(); current = current.previous; } System.out.println(); } }
在表頭插入和刪除速度很快,僅需改變一兩個引用值,因此花費 O(1) 的時間。平均起來,查找、刪除和在指定節點後面插入都須要搜索鏈表中的一半節點,須要O(N)次比較。在數組中執行這些操做也須要 O(N) 次比較,可是鏈表仍然要比數組快一些,由於當插入和刪除節點時,鏈表不須要移動任何東西,增長的效率是很顯著的,特別是當複製時間遠遠大於比較時間的時候。this
固然,鏈表比數組優越的另外一個重要方面是鏈表須要多少內存就能夠用多少內存,而且能夠擴展到全部可用內存。數組的大小在它建立的時候就固定了,因此常常因爲數組太大致使效率低下,或者數組過小致使空間溢出。可變數組能夠解決這個問題,可是它常常只容許以固定大小的增量擴展,這個解決方案在內存使用率上來講仍是比鏈表要低。spa