Java語言實現雙鏈表
阿新 • • 發佈:2018-11-17
java語言實現雙鏈表其實很簡單,雙鏈表的基本操作有:增、刪、改、差、取得指定節點的內容、判空、節點個數、清除、輸出。
相對比較難一點的是連結串列的刪除,這裡說明一下具體的實現刪除可以在外部寫一個刪除的方法,此處用的方法非常容易理解,不
用像以前那樣考慮是否為頭結點、是否為空等等,只需要兩步操作即可。具體操作在程式碼中展示:
程式碼實現如下:
interface ILink { void add(Object obj); // 增 boolean remove(Object obj); // 刪 Object set(int index, Object newData); // 替換 Object get(int index); // 取得指定節點的內容 int contains(Object data); // 判斷節點內容是否存在 int size(); // 節點個數 void clear(); // 清除 Object[] toArray(); // 將連結串列轉化為陣列 void printLink(); // 輸出 } class LinkImpl implements ILink { private Node head; // 設定頭結點 private Node last; // 設定尾節點 private int size; // 設定節點個數 private class Node { // 通過內部類設定節點 private Node pre; // 前指標 private Node next; // 後指標 private Object data; // 節點資料 public Node(Node pre, Node next, Object data) { this.pre = pre; this.next = next; this.data = data; } } @Override public void add(Object obj) { // 採用尾插的方式 Node temp = this.last; // 儲存當前連結串列的尾節點 Node newNode = new Node(temp, null, obj); // 設定新節點 this.last = newNode; // 因為是尾插的方式,先讓連結串列的尾節點指向新節點 if (this.head == null) { // 如果連結串列為空,直接插入 this.head = newNode; } else { temp.next = newNode; // 如果連結串列不為空,讓當前連結串列的尾節點指向新節點 } this.size++; // 插入節點完成,節點個數++ } @Override public boolean remove(Object obj) { if (obj == null) { // 若要刪除的節點為空節點 for (Node temp = head; temp != null; temp = temp.next) { if (temp.data == null) { // 找到空節點 unLink(temp); // 刪除 return true; } } } else { // 要刪除節點不為空 for (Node temp = head; temp != null; temp = temp.next) { if (obj.equals(temp.data)) { // 找到該節點 unLink(temp); // 刪除該節點 return true; } } } return false; } @Override public Object set(int index, Object newData) { if (!isLinkIndex(index)) { // 判斷該節點是否存在 return null; } Object result = node(index).data; // 儲存該節點的data node(index).data = newData; // 設定新的data return result; // 返回 } @Override public Object get(int index) { if (!isLinkIndex(index)) { // 判斷該節點是否存在 return null; } return node(index).data; // 返回該下標的節點 } @Override public int contains(Object data) { int i = 0; if (data == null) { // 若要查詢節點為空節點 for (Node temp = head; temp != null; temp = temp.next) { if (temp.data == null) { return i; } i++; } } else { // 若要查詢節點不為空節點 for (Node temp = head; temp != null; temp = temp.next) { if (data.equals(temp.data)) { return i; } i++; } } return -1; // 找不到返回-1 } @Override public int size() { return this.size; } @Override public void clear() { for (Node temp = head; temp != null;) { Node flag = temp.next; temp.pre = temp = temp.next = null; temp = flag; this.size--; } } @Override public Object[] toArray() { Object[] result = new Object[this.size]; int i = 0; for (Node temp = head; temp != null; temp = temp.next) { result[i++] = temp.data; } return result; } @Override public void printLink() { Object[] data = this.toArray(); for (Object temp : data) { System.out.println(temp); } } // ========================== // 根據下標返回節點 private Node node(int index) { if (index < (this.size >> 1)) { // 小於中間節點下標,從前往後找 Node temp = head; for (int i = 0; i < index; i++) { temp = temp.next; } return temp; } else { Node temp = this.last; for (int i = this.size - 1; i > index; i--) { temp = temp.pre; } return temp; } } // 判斷傳入結點的下標是否存在 private boolean isLinkIndex(int index) { return index >= 0 && index < this.size; } // 刪除節點 private void unLink(Node node) { Node nodePre = node.pre; // 儲存要刪除節點的前一個節點 Node nodeNext = node.next; // 儲存要刪除節點的下一個節點 // 先判斷前指標(pre指標域) if (node.pre == null) { // 如果要刪除節點為頭結點 this.head = nodeNext; // 當前頭結點指向該節點下一個節點 } else { nodePre.next = nodeNext; // 前一個節點的next域指向該節點的next node.pre = null; // 釋放該節點的前指標域(pre) } // 再判斷後指標(next指標域) if (node.next == null) { // 如果要刪除的節點為尾節點 this.last = nodePre; // 當前的尾節點指向該節點的前一個節點 } else { nodeNext.pre = nodePre; // 下一個節點的pre域指向該節點的pre node.next = null; // 釋放該節點的後指標域(next) } node.data = null; // 釋放該節點的值域(data) this.size--; // 節點個數減1 } }
程式碼檢測:
1、插入的檢測(採用尾插):
程式碼:
public class Test{ public static void main(String[] args) { ILink link = new LinkImpl(); link.add("頭結點"); link.add("節點1"); link.add("節點2"); link.add("節點3"); link.add("尾節點"); link.printLink(); } }
執行結果:
2、刪除操作的檢測:(如果刪除成功返回true,失敗返回false)
程式碼:
public class Test{ public static void main(String[] args) { ILink link = new LinkImpl(); link.add("頭結點"); link.add("節點1"); link.add("節點2"); link.add("節點3"); link.add("尾節點"); link.remove("節點2"); // 刪除節點2 System.out.println(link.remove("節點6")); // 刪除一個不存在的節點-->會返回false link.printLink(); } }
執行結果:
3、替換(根據指定位置替換)
程式碼:
public class Test{
public static void main(String[] args) {
ILink link = new LinkImpl();
link.add("頭結點");
link.add("節點1");
link.add("節點2");
link.add("節點3");
link.add("尾節點");
link.set(2,"Hello World!!!"); // 把下標為2的節點改為Hello World
link.printLink();
}
}
執行結果:
4、 查詢(根據下標查詢該節點的值)
程式碼:
public class Test{
public static void main(String[] args) {
ILink link = new LinkImpl();
link.add("頭結點");
link.add("節點1");
link.add("節點2");
link.add("節點3");
link.add("尾節點");
System.out.println(link.get(2)); // 查詢下標為2的節點的值
}
}
執行結果:
5、判斷連結串列中該節點是否存在(存在,返回該節點的值,不存在,返回null)
public class Test{
public static void main(String[] args) {
ILink link = new LinkImpl();
link.add("頭結點");
link.add("節點1");
link.add("節點2");
link.add("節點3");
link.add("尾節點");
System.out.println(link.get(2)); // 查詢下標為2的節點的值
System.out.println(link.get(5)); // 查詢一個不存在的節點
}
}
執行結果:
6、輸出節點的個數(清除節點後輸節點的個數)
程式碼:
public class Test {
public static void main(String[] args) {
ILink link = new LinkImpl();
link.add("頭結點");
link.add("節點1");
link.add("節點2");
link.add("節點3");
link.add("尾節點");
link.printLink();
System.out.println("==========================");
System.out.println("未清除之前節點個數為:" + link.size());
System.out.println("==========================");
link.clear();
System.out.println("清除後節點個數為:" + link.size());
}
}
執行結果: