单链表的代码实现
寫在前面:
鏈表采用一組地址任意的存儲(chǔ)單元存放線性表中的數(shù)據(jù)元素,鏈?zhǔn)浇Y(jié)構(gòu)的線性表不會(huì)按線性的邏輯順序來保存數(shù)據(jù)元素,它需要在每一個(gè)元素里保存一個(gè)引用下一個(gè)數(shù)據(jù)元素的引用(或者叫指針)。它的每個(gè)節(jié)點(diǎn)都必須包含數(shù)據(jù)元素本身和一或兩個(gè)用來引用上一個(gè)/下一個(gè)節(jié)點(diǎn)的引用。
優(yōu)點(diǎn):由于不必須按順序存儲(chǔ),鏈表在插入、刪除數(shù)據(jù)元素時(shí)比順序線性表快得多。使用鏈表結(jié)構(gòu)可以克服順序線性表(基于數(shù)組)需要預(yù)先知道數(shù)據(jù)大小的缺點(diǎn),鏈表可以充分利用計(jì)算機(jī)內(nèi)存空間,實(shí)現(xiàn)靈活的內(nèi)存動(dòng)態(tài)管理。
缺點(diǎn):鏈表在查找一個(gè)節(jié)點(diǎn)或者訪問特點(diǎn)編號(hào)的節(jié)點(diǎn)則比順序線性表慢得多。由于鏈表結(jié)構(gòu)失去了數(shù)組隨機(jī)存取的優(yōu)點(diǎn),同時(shí)鏈表由于增加了節(jié)點(diǎn)的指針域,空間開銷比較大。
以下使用Java語言實(shí)現(xiàn)一個(gè)單鏈表:
1 package com.ietree.basic.datastructure.linklist; 2 3 /** 4 * 鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu) 5 * 6 * @param <T> 7 * @author Dylan 8 */ 9 public class LinkList<T> { 10 11 // 定義一個(gè)內(nèi)部類Node,Node實(shí)例代表鏈表的節(jié)點(diǎn) 12 private class Node { 13 14 // 保存節(jié)點(diǎn)的數(shù)據(jù) 15 private T data; 16 // 指向下一個(gè)節(jié)點(diǎn)的引用 17 private Node next; 18 // 無參構(gòu)造器 19 public Node() { 20 } 21 // 初始化全部屬性的構(gòu)造器 22 public Node(T data, Node next) { 23 this.data = data; 24 this.next = next; 25 } 26 } 27 28 // 保存該鏈表的頭節(jié)點(diǎn) 29 private Node header; 30 // 保存該鏈表的尾節(jié)點(diǎn) 31 private Node tail; 32 // 保存該鏈表中已包含的節(jié)點(diǎn)數(shù) 33 private int size; 34 35 // 創(chuàng)建空鏈表 36 public LinkList() { 37 // 空鏈表,header和tail都是null 38 header = null; 39 tail = null; 40 } 41 42 // 以指定數(shù)據(jù)元素來創(chuàng)建鏈表,該鏈表只有一個(gè)元素 43 public LinkList(T element) { 44 45 header = new Node(element, null); 46 tail = header; 47 size++; 48 49 } 50 51 // 返回鏈表的長(zhǎng)度 52 public int length() { 53 54 return size; 55 56 } 57 58 // 獲取鏈?zhǔn)骄€性表中索引為index處的元素 59 public T get(int index) { 60 61 return getNodeByIndex(index).data; 62 63 } 64 65 // 根據(jù)索引index獲取指定位置的節(jié)點(diǎn) 66 public Node getNodeByIndex(int index) { 67 68 if (index < 0 || index > size - 1) { 69 70 throw new IndexOutOfBoundsException("線性表索引越界"); 71 72 } 73 74 // 從header節(jié)點(diǎn)開始 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 // 查找鏈?zhǔn)骄€性表中指定元素的索引 86 public int locate(T element) { 87 88 // 從頭節(jié)點(diǎn)開始搜索 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 // 向線性表的指定位置插入一個(gè)元素 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 // 當(dāng)index為0時(shí),即在鏈表頭處插入 114 if (index == 0) { 115 116 addAtHeader(element); 117 118 } else { 119 120 // 獲取插入點(diǎn)的前一個(gè)節(jié)點(diǎn) 121 Node prev = getNodeByIndex(index - 1); 122 // 讓prev的next指向新節(jié)點(diǎn),讓新節(jié)點(diǎn)的next引用指向原來prev的下一個(gè)節(jié)點(diǎn) 123 prev.next = new Node(element, prev.next); 124 size++; 125 126 } 127 } 128 } 129 130 // 采用尾插法為鏈表添加新節(jié)點(diǎn) 131 public void add(T element) { 132 133 // 如果該鏈表還是空鏈表 134 if (header == null) { 135 136 header = new Node(element, null); 137 // 只有一個(gè)節(jié)點(diǎn),header、tail都指向該節(jié)點(diǎn) 138 tail = header; 139 140 } else { 141 142 // 創(chuàng)建新節(jié)點(diǎn) 143 Node newNode = new Node(element, null); 144 // 讓尾節(jié)點(diǎn)的next指向新增的節(jié)點(diǎn) 145 tail.next = newNode; 146 // 以新增節(jié)點(diǎn)作為新的尾節(jié)點(diǎn) 147 tail = newNode; 148 149 } 150 size++; 151 } 152 153 // 采用頭插法為鏈表添加新節(jié)點(diǎn) 154 public void addAtHeader(T element) { 155 156 // 創(chuàng)建新節(jié)點(diǎn),讓新節(jié)點(diǎn)的next指向原來的header 157 // 并以新節(jié)點(diǎn)作為新的header 158 header = new Node(element, header); 159 // 如果插入之前是空鏈表 160 if (tail == null) { 161 162 tail = header; 163 164 } 165 size++; 166 } 167 168 // 刪除鏈?zhǔn)骄€性表中指定索引處的元素 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節(jié)點(diǎn) 178 if (index == 0) { 179 180 del = header; 181 header = header.next; 182 183 } else { 184 185 // 獲取刪除點(diǎn)的前一個(gè)節(jié)點(diǎn) 186 Node prev = getNodeByIndex(index - 1); 187 // 獲取將要被刪除的節(jié)點(diǎn) 188 del = prev.next; 189 // 讓被刪除節(jié)點(diǎn)的next指向被刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) 190 prev.next = del.next; 191 // 將被刪除節(jié)點(diǎn)的next引用賦為null 192 del.next = null; 193 194 } 195 size--; 196 return del.data; 197 } 198 199 // 刪除鏈?zhǔn)骄€性表中最后一個(gè)元素 200 public T remove() { 201 202 return delete(size - 1); 203 204 } 205 206 // 判斷鏈?zhǔn)骄€性表是否為空表 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 // 鏈表為空鏈表時(shí) 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 }測(cè)試類:
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?
轉(zhuǎn)載于:https://www.cnblogs.com/Dylansuns/p/6783682.html
總結(jié)
- 上一篇: Linux内核分析 - 网络
- 下一篇: stl_alloc.h分配器