一,鏈表的概念及結構
- 概念:
鏈表是一種物理存儲結構上非連續存儲結構,數據元素的邏輯順序是經過鏈表中的引用連接次序實現的。html
-
結構:
實際中鏈表的結構很是多樣,如下狀況組合起來就有八種鏈表結構;node- 單向 , 雙向
- 帶頭 , 不帶頭
- 循環 , 非循環
二,代碼實現
下面只介紹無頭單向非循環鏈表的實現測試
- 代碼實現:
// 一個節點 class Node { public int data; // 數據 public Node next = null; // 下一個節點的位置 public Node(int data) { this.data = data; } } public class LinkedList { // 管理全部的鏈表節點. 只須要記錄頭結點的位置便可 // 初始狀況下 head 爲 null, 此時表示空鏈表(不帶傀儡節點) private Node head = null; // private Node tail = null; // 優化尾插 // private int size = 0; // 優化獲取長度 public void addFirst(int data) { // 1. 根據 data 值構建一個鏈表節點(Node對象) Node node = new Node(data); // 2. 若是鏈表爲空鏈表 if (head == null) { head = node; return; }
語言 | 方法 |
---|---|
3013 | Hsg7R912UO |
tRLDU | 抖音文案 |
4267 | 2012-08-16 04:24:30 |
// 3. 若是鏈表不是空鏈表 node.next = head; head = node; } public void addLast(int data) { // 1. 根據 data 構造一個 Node 對象 Node node = new Node(data); // 2. 若是鏈表爲空鏈表 if (head == null) { head = node; return; } // 3. 若是鏈表非空, 須要先找到這個鏈表末尾的最後一個節點 Node tail = head; while (tail.next != null) { tail = tail.next; } // 循環結束以後, tail 就對應到最後一個節點了 tail.next = node; } public void display() { // 把鏈表中的每一個元素都打印出來 for (Node cur = head; cur != null; cur = cur.next) { System.out.print(cur.data + " "); } System.out.println(); } public int getSize() { int size = 0; for (Node cur = head; cur != null; cur = cur.next) { size++; } return size; } // 插入成功, 返回 true, 不然 false public boolean addIndex(int index, int data) { int size = getSize(); // 1. 斷定 index 是否有效 if (index < 0 || index > size) { // index 無效, 插入失敗 return false; } // 2. 若是 index 爲 0, 至關於頭插 if (index == 0) { addFirst(data); return true; } // 3. 若是 index 爲 size, 至關於尾插 if (index == size) { addLast(data); return true; } Node node = new Node(data); // 4. 若是 index 是一箇中間的位置 // a) 先找到 index 的前一個節點 index - 1 Node prev = getPos(index - 1); // b) 接下來就把新節點插入到 prev 以後 // 註釋是頭插的代碼 // node.next = head; // head = node; node.next = prev.next; prev.next = node; return true; }
- 代碼測試
// 給定 index 下標, 找到對應的節點 private Node getPos(int index) { Node cur = head; for (int i = 0; i < index; i++) { // cur.next 操做以前必需要保證 // cur 是非 null 的 cur = cur.next; } return cur; } public boolean contains(int toFind) { for (Node cur = head; cur != null; cur = cur.next) { if (cur.data == toFind) { return true; } } return false; } public void remove(int toRemove) { // 1. 若是要刪除元素是頭結點, 特殊處理一下 if (head.data == toRemove) { // 頭結點要被刪掉 head = head.next; return; } // 2. 若是要刪除元素不是頭結點, 找到要刪除節點的前一個位置 Node prev = searchPrev(toRemove); // 3. 修改引用的指向, 完成刪除 // prev.next = prev.next.next; Node toDelete = prev.next; prev.next = toDelete.next; } private Node searchPrev(int toRemove) { // 找到 toRemove 的前一個節點 for (Node cur = head; cur != null && cur.next != null; cur = cur.next) { if (cur.next.data == toRemove) { return cur; } } return null; } public void removeAll(int toRemove) { // 1. 先刪除非頭結點, 須要找到待刪除節點的前一個位置 // prev 始終指向 cur 的前一個位置 Node prev = head; Node cur = head.next; while (cur != null) { if (cur.data == toRemove) { // cur 節點須要被刪除掉 prev.next = cur.next; cur = prev.next; } else { // prev 和 cur 同步日後移動 prev = cur; cur = cur.next; } } // 2. 處理頭結點爲要刪除節點的狀況 if (head.data == toRemove) { head = head.next; } } public void clear() { head = null; } }
- 測試代碼
public class Test{ private static void testAddFirst(){ //測試頭插 LinkedList6 List = new LinkedList6(); List.addFirst(1); List.addFirst(1); List.addFirst(1); List.addFirst(1); List.display(); //測試鏈表打印 int size = List.getSize(); //測試獲取鏈表長度 System.out.println(size); } private static void testAddLast(){ //測試尾插 LinkedList6 List1 = new LinkedList6(); List1.addLast(1); List1.addLast(2); List1.addLast(3); List1.addLast(4); List1.addLast(5); List1.display(); List1.addIndex(2,8); //測試指定位置插入 List1.display(); boolean result = List1.contains(10); //測試鏈表是否包含某個元素 System.out.println(result); List1.remove(8); //測試刪除鏈表中指定節點(從左到右第一個出現的) List1.display(); List1.addLast(1); List1.addLast(1); List1.addLast(1); List1.display(); List1.removeAll(1); //測試刪除鏈表中指定元素的全部節點 List1.display(); List1.clear(); //測試清空鏈表 List1.display(); } public static void main(String[] args){ //testAddFirst(); testAddLast(); } }