1.獲取鏈表第i個數據的算法思路
- 聲明一個結點p指向鏈表第一個結點,初始化j從1開始
- 當j<i時,就遍歷鏈表,讓p的指針向后移動,不斷指向下一結點,j累加1
- 若到鏈表末尾p為空,則說明第i個元素不存在
- 否則查找成功,返回結點p的數據
2.單鏈表第i個數據插入結點的算法思路
- 聲明一結點p指向鏈表第一個結點,初始化j從1開始
- 當j<i時,就遍歷鏈表,讓p的指針向后移動,不斷指向下一結點,j累加1
- 若到鏈表末尾p為空,則說明第i個元素不存在
- 否則查找成功,在系統中生成一個空結點s
- 將數據元素e賦值給s->data
- 單鏈表的插入標准語句s->next=p->next;p->next=s
- 返回成功
3.單鏈表第i個數據刪除結點的算法思路
- 聲明一結點p指向鏈表第一個結點,初始化j從1開始
- 當j<i時,就遍歷鏈表,讓p的指針向后移動,不斷指向下一結點,j累加1
- 若到鏈表末尾p為空,則說明第i個元素不存在
- 否則查找成功,將欲刪除的結點p->next賦值給q
- 單鏈表的刪除標准語句p->next=q->next
- 將q結點中的數據賦值給e,作為返回
- 釋放q結點
- 返回成功
分析一下剛才我們講解的單鏈表插入和刪除算法,我們發現,它們其實都是由兩部分組成:第一部分就是遍歷查找第i個結點;第二部分就是插入和刪除結點。
4.單鏈表整表創建的算法思路
- 聲明一結點p和計數器變量i
- 初始化一空鏈表L
- 讓L的頭結點的指針指向NULL,即建立一個帶頭結點的單鏈表
- 循環:
- 生成一新結點賦值給p
- 隨機生成一數字賦值給p的數據域p->data
- 將p插入到頭結點與前一新節點之間
頭插法,尾插法
5.單鏈表的整表刪除
- 聲明一結點p和q
- 將第一個結點賦值給p
- 循環:
- 將下一結點賦值給q
- 釋放p
- 將q賦值給p
Java代碼實現,以下代碼實現了單鏈表的各種操作
/** * 結點類的描述 * * 單鏈表是由若干個結點連接而成,要實現單鏈表,首先需要設計結點類 * * 結點類由data和next組成 * * data是數據域,用來存放數據元素的值 * next是指針域,用來存放后繼結點的地址 * * @author acer * */ public class Node { private Object data; //存放結點值 private Node next; //后繼結點的引用 //無參數時的構造方法 public Node() { this(null, null); } //帶一個參數的構造方法 public Node(Object data) { this(data, null); } //帶兩個參數的構造方法 public Node(Object data, Node next) { this.data = data; this.next = next; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }
創建一個接口
public interface IList { public void clear(); public boolean isEmpty(); public int length(); public Object get(int i) throws Exception; public void insert(int i, Object x) throws Exception; public void remove(int i) throws Exception; public int indexOf(Object x); public void display(); }
/** * 單鏈表類的描述 * * 由於單鏈表只需一個頭指針就能唯一的標示它,所以單鏈表類的成員變量只需設置一個頭指針即可 * * @author acer * */ public class LinkList implements IList { //單鏈表的頭指針 private Node head; public LinkList() { //初始化頭結點 head = new Node(); } public LinkList(int n, boolean Order) throws Exception { this(); if (Order) { create1(n); } else { create2(n); } } // 用尾插法順序建立單鏈表,其中n為單鏈表的結點個數 public void create1(int n) throws Exception { //構造用於輸入對象 Scanner sc = new Scanner(System.in); for(int j = 0; j < n; j++) { //生成新結點,插入到表尾 insert(length(), sc.next()); } } // 用頭插法逆位序建立單鏈表,其中n為單鏈表的結點個數 public void create2(int n) throws Exception { /* * 構造用於輸入對象 * * Scanner 使用分隔符模式將其輸入分解為標記,默認情況下該分隔符模式與空白匹配 * 然后可以使用不同的 next 方法將得到的標記轉換為不同類型的值。 */ Scanner sc = new Scanner(System.in); for (int j = 0; j < n; j++) { //生成新結點,插入到表頭 insert(0, sc.next()); } } // 將一個已經存在的帶頭結點單鏈表置為空表 @Override public void clear() { head.setData(null); head.setNext(null); } // 判斷帶頭結點的單鏈表是否為空 @Override public boolean isEmpty() { return head.getNext() == null; } // 求帶頭結點的單鏈表的長度 @Override public int length() { Node p = head.getNext(); int lenth = 0; while(p != null) { p = p.getNext(); ++lenth; } return lenth; } /* * 讀取帶頭結點的單鏈表中的第i個結點 * * 時間復雜度為O(n) */ @Override public Object get(int i) throws Exception { // 初始化,p指向首結點,j為計數器 Node p = head.getNext(); int j = 0; // 從首結點開始向后查找,直到p指向第i個結點或p為空 while (p != null && j < i) { // 指向后繼結點 p = p.getNext(); // 極速器加1 ++j; } // i小於0或者大於表長減1 if (j > i || p == null) { // 拋出異常 throw new Exception("第" + i + "個元素不存在"); } // 返回結點p的數據域的值 return p.getData(); } /* * 在帶頭結點的單鏈表中的第i個結點之前插入一個值為x的新結點 * * 時間復雜度為O(n) */ @Override public void insert(int i, Object x) throws Exception { // 初始化,p指向首結點,j為計數器 Node p = head; int j = -1; // 尋找第i個結點的前驅 while (p != null && j < i - 1) { p = p.getNext(); // 計數器加1 ++j; } // i不合法 if (j > i - 1 || p == null) { // 拋出異常 throw new Exception("插入位置不合法"); } // 生成新結點 Node s = new Node(x); // 修改鏈,使新結點插入到單鏈表中 s.setNext(p.getNext()); p.setNext(s); } /* * 在不帶頭結點的單鏈表的第i個結點之前插入一個數據域值為x的新結點 * * 時間復雜度為O(n) */ public void insert2(int i, Object x) throws Exception { // 初始化,p指向首結點,j為計數器 Node p = head; int j = 0; // 用i = -1\0\1測試 while (p != null && j < i - 1) { p = p.getNext(); ++j; } if (j > i || p == null) { throw new Exception("插入位置不合法"); } Node s = new Node(x); // 插入位置為表頭時 if (i == 0) { s.setNext(head); head = s; } // 插入位置為表的中間或表尾時 else { s.setNext(p.getNext()); p.setNext(s); } } /* * 刪除單鏈表中的第i個結點 * * 時間復雜度為O(n) */ @Override public void remove(int i) throws Exception { // 初始化,p指向首結點,j為計數器 Node p = head; int j = -1; // 尋找第i個結點的前驅 while (p.getNext() != null && j < i - 1) { p = p.getNext(); ++j; } if (j > i - 1 || p.getNext() == null) { throw new Exception("刪除位置不合法"); } // 修改鏈指針,使待刪除結點從單鏈表中脫離 p.setNext(p.getNext().getNext()); } /* * 在單鏈表中查找值為x的結點 * * 時間復雜度為O(n) */ @Override public int indexOf(Object x) { // 初始化,p指向首結點,j為計數器 Node p = head.getNext(); int j = 0; // 下面從單鏈表中的首結點開始查找,直到p.getData()為x或到達單鏈表的表尾 while (p != null && !p.getData().equals(x)) { // 指向下一個結點 p = p.getNext(); // 計數器加1 ++j; } // 若p指向單鏈表中的某個結點,返回值為x的結點在單鏈表中的位置 if (p != null) { return j; } else { // 值為x的結點不在鏈表中 return -1; } } // 輸出單鏈表中的所有結點 @Override public void display() { //取出帶頭結點的單鏈表中的首結點 Node p = head.getNext(); while(p != null) { //輸出結點的值 System.out.print(p.getData() + " "); //取下一個結點 p = p.getNext(); } //換行 System.out.println(); } }