單鏈表的代碼實現


寫在前面:

  鏈表采用一組地址任意的存儲單元存放線性表中的數據元素,鏈式結構的線性表不會按線性的邏輯順序來保存數據元素,它需要在每一個元素里保存一個引用下一個數據元素的引用(或者叫指針)。它的每個節點都必須包含數據元素本身和一或兩個用來引用上一個/下一個節點的引用。

優點:由於不必須按順序存儲,鏈表在插入、刪除數據元素時比順序線性表快得多。使用鏈表結構可以克服順序線性表(基於數組)需要預先知道數據大小的缺點,鏈表可以充分利用計算機內存空間,實現靈活的內存動態管理。

缺點:鏈表在查找一個節點或者訪問特點編號的節點則比順序線性表慢得多。由於鏈表結構失去了數組隨機存取的優點,同時鏈表由於增加了節點的指針域,空間開銷比較大。

以下使用Java語言實現一個單鏈表:

  1 package com.ietree.basic.datastructure.linklist;
  2 
  3 /**
  4  * 鏈式存儲結構
  5  * 
  6  * @param <T>
  7  * @author Dylan
  8  */
  9 public class LinkList<T> {
 10 
 11     // 定義一個內部類Node,Node實例代表鏈表的節點
 12     private class Node {
 13         
 14         // 保存節點的數據
 15         private T data;
 16         // 指向下一個節點的引用
 17         private Node next;
 18         // 無參構造器
 19         public Node() {
 20         }
 21         // 初始化全部屬性的構造器
 22         public Node(T data, Node next) {
 23             this.data = data;
 24             this.next = next;
 25         }
 26     }
 27     
 28     // 保存該鏈表的頭節點
 29     private Node header;
 30     // 保存該鏈表的尾節點
 31     private Node tail;
 32     // 保存該鏈表中已包含的節點數
 33     private int size;
 34     
 35     // 創建空鏈表
 36     public LinkList() {
 37         // 空鏈表,header和tail都是null
 38         header = null;
 39         tail = null;
 40     }
 41     
 42     // 以指定數據元素來創建鏈表,該鏈表只有一個元素
 43     public LinkList(T element) {
 44         
 45         header = new Node(element, null);
 46         tail = header;
 47         size++;
 48         
 49     }
 50     
 51     // 返回鏈表的長度
 52     public int length() {
 53         
 54         return size;
 55         
 56     }
 57     
 58     // 獲取鏈式線性表中索引為index處的元素
 59     public T get(int index) {
 60 
 61         return getNodeByIndex(index).data;
 62 
 63     }
 64     
 65     // 根據索引index獲取指定位置的節點
 66     public Node getNodeByIndex(int index) {
 67 
 68         if (index < 0 || index > size - 1) {
 69             
 70             throw new IndexOutOfBoundsException("線性表索引越界");
 71             
 72         }
 73         
 74         // 從header節點開始
 75         Node current = header;
 76         for (int i = 0; i < size && current != null; i++, current = current.next) {
 77             if (i == index) {
 78                 return current;
 79             }
 80         }
 81 
 82         return null;
 83     }
 84     
 85     // 查找鏈式線性表中指定元素的索引
 86     public int locate(T element) {
 87         
 88         // 從頭節點開始搜索
 89         Node current = header;
 90         for (int i = 0; i < size && current != null; i++, current = current.next) {
 91             if (current.data.equals(element)) {
 92                 return i;
 93             }
 94         }
 95         return -1;
 96     }
 97     
 98     // 向線性表的指定位置插入一個元素
 99     public void insert(T element, int index) {
100         
101         if (index < 0 || index > size) {
102             
103             throw new IndexOutOfBoundsException("線性表索引越界");
104             
105         }
106         
107         // 如果還是空鏈表
108         if (header == null) {
109             
110             add(element);
111             
112         } else {
113             // 當index為0時,即在鏈表頭處插入
114             if (index == 0) {
115                 
116                 addAtHeader(element);
117                 
118             } else {
119                 
120                 // 獲取插入點的前一個節點
121                 Node prev = getNodeByIndex(index - 1);
122                 // 讓prev的next指向新節點,讓新節點的next引用指向原來prev的下一個節點
123                 prev.next = new Node(element, prev.next);
124                 size++;
125                 
126             }
127         }
128     }
129     
130     // 采用尾插法為鏈表添加新節點
131     public void add(T element) {
132         
133         // 如果該鏈表還是空鏈表
134         if (header == null) {
135             
136             header = new Node(element, null);
137             // 只有一個節點,header、tail都指向該節點
138             tail = header;
139             
140         } else {
141             
142             // 創建新節點
143             Node newNode = new Node(element, null);
144             // 讓尾節點的next指向新增的節點
145             tail.next = newNode;
146             // 以新增節點作為新的尾節點
147             tail = newNode;
148             
149         }
150         size++;
151     }
152     
153     // 采用頭插法為鏈表添加新節點
154     public void addAtHeader(T element) {
155         
156         // 創建新節點,讓新節點的next指向原來的header
157         // 並以新節點作為新的header
158         header = new Node(element, header);
159         // 如果插入之前是空鏈表
160         if (tail == null) {
161             
162             tail = header;
163             
164         }
165         size++;
166     }
167     
168     // 刪除鏈式線性表中指定索引處的元素
169     public T delete(int index) {
170         
171         if (index < 0 || index > size - 1) {
172             
173             throw new IndexOutOfBoundsException("線性表索引越界");
174             
175         }
176         Node del = null;
177         // 如果被刪除的是header節點
178         if (index == 0) {
179             
180             del = header;
181             header = header.next;
182             
183         } else {
184             
185             // 獲取刪除點的前一個節點
186             Node prev = getNodeByIndex(index - 1);
187             // 獲取將要被刪除的節點
188             del = prev.next;
189             // 讓被刪除節點的next指向被刪除節點的下一個節點
190             prev.next = del.next;
191             // 將被刪除節點的next引用賦為null
192             del.next = null;
193             
194         }
195         size--;
196         return del.data;
197     }
198     
199     // 刪除鏈式線性表中最后一個元素
200     public T remove() {
201         
202         return delete(size - 1);
203         
204     }
205     
206     // 判斷鏈式線性表是否為空表
207     public boolean empty() {
208         
209         return size == 0;
210         
211     }
212     
213     // 清空線性表
214     public void clear() {
215         
216         // 將header、tail賦為null
217         header = null;
218         tail = null;
219         size = 0;
220         
221     }
222     
223     public String toString() {
224         
225         // 鏈表為空鏈表時
226         if (empty()) {
227 
228             return "[]";
229 
230         } else {
231 
232             StringBuilder sb = new StringBuilder("[");
233             for (Node current = header; current != null; current = current.next) {
234                 sb.append(current.data.toString() + ", ");
235             }
236             int len = sb.length();
237             return sb.delete(len - 2, len).append("]").toString();
238             
239         }
240     }
241 }

測試類:

 1 package com.ietree.basic.datastructure.linklist;
 2 
 3 public class LinkListTest {
 4     public static void main(String[] args) {
 5 
 6         LinkList<String> list = new LinkList<String>();
 7         list.insert("aaaa", 0);
 8         list.add("bbbb");
 9         list.add("cccc");
10         list.insert("dddd", 1);
11         System.out.println(list);
12         list.delete(2);
13         System.out.println(list);
14         System.out.println("cccc在鏈表中的位置:" + list.locate("cccc"));
15         System.out.println("鏈表中索引2處的元素:" + list.get(2));
16     }
17 }

程序輸出:

[aaaa, dddd, bbbb, cccc]
[aaaa, dddd, cccc]
cccc在鏈表中的位置:2
鏈表中索引2處的元素:cccc

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM