一.单向链表(递归)
MyLinkList类
1 package List; 2 3 // 单向链表 4 public class MyLinkList { 5 private Node root; // 根结点 6 private int size; // 结点个数 7 private int index; // 脚标 8 private Object[] reData; // 保存数据的数组 9 10 // 构造方法 11 public MyLinkList() { 12 this.root = new Node("head"); 13 System.out.println("创建了带头指针的链表"); 14 } 15 16 public MyLinkList(Object data) { 17 if (data == null) 18 System.out.println("参数错误"); 19 this.root = new Node(data); 20 this.size++; 21 System.out.println("创建成功" + data); 22 } 23 24 // 是否是空表 25 public boolean isEmpty() { 26 return this.size == 0; 27 } 28 29 // 返回长度 30 public int size() { 31 return this.size; 32 } 33 34 // 清空链表 35 public void clear(){ 36 this.root = null; 37 this.size = 0; 38 } 39 40 // 判断两个链表是否相等 41 public boolean equals(Object obj){ 42 // 常规判断 43 if(obj == null) 44 return false; 45 if(obj == this) 46 return true; 47 48 // 是MyLinkList类 49 if(obj instanceof MyLinkList){ 50 MyLinkList linkList = (MyLinkList)obj; 51 52 // 根结点相同 53 if(!this.root.data.equals(linkList.root.data)){ 54 System.out.println("根节点不相同"); 55 return false; 56 } 57 // 长度相同 58 if(this.size != linkList.size) { 59 System.out.println("长度不同"); 60 return false; 61 } 62 63 // 各个结点相同 64 if(this.size==1){ // 只含有根结点 65 return true; 66 } 67 return this.root.next.equals(linkList.root.next); 68 } 69 70 // 不是MyLinkList类 71 return false; 72 73 } 74 75 // 添加单个数据 76 public boolean addData(Object data) { 77 if (data == null) { 78 System.out.println("参数错误"); 79 return false; 80 } 81 82 // 把data封装成带指针域的结点 83 Node node = new Node(data); 84 85 if (this.root.next == null) 86 this.root.next = node; 87 else 88 this.root.next.addNode(node); 89 System.out.println("添加成功" + data); 90 this.size++; 91 return true; 92 } 93 94 // 添加多个数据 95 public boolean addDatas(Object[] datas) { 96 if (datas == null) { 97 System.out.println("参数错误"); 98 return false; 99 } 100 101 // 循环添加结点 102 for (int index = 0; index < datas.length; ++index) { 103 Node data = new Node(datas[index]);// 封装结点 104 this.root.addNode(data); 105 this.size++; 106 } 107 return true; 108 } 109 110 // 查找数据是否存在 111 public boolean contains(Object data) { 112 if (data == null || this.isEmpty()) 113 return false; 114 return this.root.containsNode(data); 115 } 116 117 // 查找指定位置下的数据 118 public Object get(int index) { 119 // 参数错误 120 if (this.isEmpty() || index < 0 || index > this.size) 121 return null; 122 123 if (this.root.data.equals("head")) { // 带头指针 124 if (index == 1) // 返回第一个有效数据 125 return this.root.next.data; 126 else { 127 this.index = 0; 128 return this.root.next.getNode(index); 129 } 130 } else { // 不带头指针 131 if (index == 1) // 返回第一个有效数据 132 return this.root.data; 133 else { 134 this.index = 1; 135 return this.root.next.getNode(index); 136 } 137 138 } 139 } 140 141 // 删除数据 142 public boolean deleteData(Object data) { 143 if (data == null || this.isEmpty()) { 144 return false; 145 } 146 // 是根结点 147 if (this.root.data.equals(data)) { 148 this.root = this.root.next; 149 this.size--; 150 return true; 151 } 152 153 // 不是根节点 154 else 155 return this.root.deleteNode(data); 156 } 157 158 // 打印所有数据 159 public void print() { 160 if (this.isEmpty()) 161 System.out.print("空表--------"); 162 else 163 this.root.printNode(); 164 System.out.println(""); 165 } 166 167 // 返回数组数据 168 public Object[] toArray() { 169 if (this.isEmpty()) 170 return null; 171 172 // 数组保存 173 this.index = 0; // 数组下标 174 if (this.root.data.equals("head")) // 链表带头指针 175 reData = new Object[++this.size]; 176 else 177 reData = new Object[this.size]; 178 this.root.toArray(); 179 return reData; 180 } 181 182 // 结点类(内部) 183 class Node { 184 Object data; // 数据域 185 Node next; // 指针域 186 187 // 构造方法 188 public Node(Object data) { 189 this.data = data; 190 } 191 192 // 添加结点 193 public void addNode(Node node) { 194 if (this.next == null) 195 this.next = node; 196 else 197 this.next.addNode(node); 198 } 199 200 // 打印结点数据 201 public void printNode() { 202 System.out.print(this.data + " "); 203 if (this.next != null) 204 this.next.printNode(); 205 } 206 207 // 删除结点 208 public boolean deleteNode(Object data) { 209 if (this.next == null) { 210 System.out.println("删除失败" + data); 211 return false; 212 } 213 if (this.next.data.equals(data)) { 214 System.out.println("删除成功" + this.next.data); 215 MyLinkList.this.size--; 216 this.next = this.next.next; 217 return true; 218 } 219 return this.next.deleteNode(data); 220 } 221 222 // 返回数组 223 public void toArray() { 224 MyLinkList.this.reData[MyLinkList.this.index++] = this.data; 225 if (this.next != null) 226 this.next.toArray(); 227 } 228 229 // 查找指定结点 230 public Object getNode(int index) { 231 if (++MyLinkList.this.index == index) 232 return this.data; 233 return this.next.getNode(index); 234 } 235 236 // 查找结点 237 public boolean containsNode(Object data) { 238 if (this.data == data) 239 return true; 240 if (this.next != null) 241 return this.next.containsNode(data); 242 return false; 243 } 244 245 // 重写equals() 246 public boolean equals(Node node){ 247 // 数据域是否相同 248 if(!this.data.equals(node.data)) { 249 System.out.println("数据域不同this:"+this.data+" linkList:"+node.data); 250 return false; 251 } 252 // 还有下个结点 253 if(this.next!=null) 254 return this.next.equals(node.next); 255 // 没有下个结点且到目前为止所有结点数据域相同 256 return true; 257 258 } 259 } 260 }
TestMyLinkList类
1 package List; 2 3 // 单向链表测试 4 public class TestMyLinkList { 5 6 public static void main(String[] args) { 7 // 创建一个链表 8 MyLinkList linkList = new MyLinkList(5); 9 10 // 初始化一个链表 11 for (int index = 1; index < 10; ++index) { 12 int num = (int) (Math.random() * 11); 13 linkList.addData(num); 14 } 15 16 // 打印链表的所有数据 17 linkList.print(); 18 19 // 删除结点 20 linkList.deleteData(5); 21 linkList.print(); 22 linkList.deleteData(10); 23 linkList.print(); 24 25 System.out.println("第2个结点数据:" + linkList.get(2)); 26 // 数组化 27 Object[] data = new Object[linkList.size()]; 28 data = linkList.toArray(); 29 for (Object index : data) 30 System.out.print(index + " "); 31 System.out.println(""); 32 System.out.println("-------------------"); 33 // 创建一个链表 34 MyLinkList linkList2 = new MyLinkList(); 35 36 // 待添加数据的数组 37 Object[] datas = { 5, "123", 26 }; 38 linkList2.addDatas(datas); 39 System.out.println("包含'5'吗" + linkList2.contains(5)); 40 linkList2.print(); 41 System.out.println("----------------------------"); 42 // 创建一个链表 43 MyLinkList linkList1 = new MyLinkList(); 44 linkList1.addDatas(datas); 45 linkList1.print(); 46 System.out.println("是否相等"+linkList2.equals(linkList1)); 47 } 48 49 }
打印
1 添加成功5 2 添加成功1 3 添加成功6 4 添加成功6 5 添加成功6 6 添加成功1 7 添加成功5 8 添加成功2 9 添加成功10 10 5 5 1 6 6 6 1 5 2 10 11 5 1 6 6 6 1 5 2 10 12 删除成功10 13 5 1 6 6 6 1 5 2 14 第2个结点数据:1 15 5 1 6 6 6 1 5 2 16 ------------------- 17 包含'5'吗true 18 head 5 123 26 19 ---------------------------- 20 head 5 123 26 21 是否相等true
总结:1.避免空指针异常(NullPointException):先判断引用是否为null,后使用。
参考:https://www.cnblogs.com/dolphin0520/p/3811445.html
2018-7-19
二、双向链表(循环、头插法)
DoubleLink类
1 package List; 2 3 // 双向链表(循坏、头插法) 4 public class DoubleLink { 5 private Node root; // 表头 6 private int size; // 长度 7 8 // 结点类 9 private class Node { 10 Object data; // 数据域 11 Node prev; // 前趋 12 Node next; // 后继 13 14 // 构造方法 15 public Node(Object data, Node prev, Node next) { 16 this.data = data; 17 this.prev = prev; 18 this.next = next; 19 } 20 21 public Node(Object data) { 22 this.data = data; 23 } 24 } 25 26 // 构造方法 27 public DoubleLink() { 28 this.root = new Node(null, null, null); 29 this.root.prev = this.root.next = this.root; 30 this.size = 0; 31 } 32 33 // 是否是空表 34 public boolean isEmpty() { 35 return this.size == 0; 36 } 37 38 // 返回长度 39 public int size() { 40 return this.size; 41 } 42 43 // 添加数据 44 public boolean addData(Object data) { 45 // 空引用 46 if (data == null) 47 return false; 48 49 this.size++; // 增加长度 50 Node node = new Node(data); // 封装结点 51 // 添加结点 52 53 if (this.isEmpty()) { 54 this.root.next = node; 55 this.root.prev = node; 56 57 node.next = this.root; 58 node.prev = this.root; 59 return true; 60 } 61 62 // 头插法 63 node.next = this.root.next; // 将新结点的后继指向头结点的后继 64 node.prev = this.root; // 将新结点的前驱指向头结点 65 this.root.next.prev = node; // 头结点的后继结点的前驱指向新结点 66 this.root.next = node; // 头结点的后继节点指向新结点 67 return true; 68 } 69 70 // 查找第index结点 71 private Node getNode(int index) { 72 Node oldNode = this.root; 73 int foot = 0; // 脚标 74 if (index <= this.size / 2) { // 正查找 75 System.out.print("正查"); 76 while (true) { 77 if (foot++ == index) 78 break; 79 oldNode = oldNode.next; 80 } 81 } else { 82 int LIndex = this.size + 1 - index; 83 System.out.print("反查"); 84 while (true) { 85 if (foot++ == LIndex) 86 break; 87 oldNode = oldNode.prev; 88 } 89 } 90 System.out.print(oldNode.data); 91 return oldNode; 92 } 93 94 // 查找结点 95 private Node getNode(Object data) { 96 Node oldNode = this.root.next; 97 while (true) { 98 if (oldNode.data.equals(data)) 99 return oldNode; 100 if (oldNode.next.data == null) 101 return null; 102 oldNode = oldNode.next; 103 } 104 105 } 106 107 // 删除结点 108 private void removeNode(Node node) { 109 node.next.prev = node.prev; // 结点的后继结点的前驱指向结点的前驱 110 node.prev.next = node.next; // 结点的前驱结点的后继指向结点的后继 111 node = null; 112 } 113 114 // 前插法 115 private boolean addNode(Node oldNode, Node newNode) { 116 oldNode.prev.next = newNode; 117 newNode.prev = oldNode.prev; 118 oldNode.prev = newNode; 119 newNode.next = oldNode; 120 return true; 121 } 122 123 // 在index结点前插入新结点 124 public boolean addData(Object data, int index) { 125 if (data == null) 126 return false; 127 if (index <= 0 || index > this.size) 128 return false; 129 130 Node newNode = new Node(data); // 封装结点 131 132 // 查找结点 133 Node oldNode = getNode(index); 134 this.size++; // 增加长度 135 // 更改指针域 136 return addNode(oldNode, newNode); 137 } 138 139 // 得到第index个结点的数据 140 public Object get(int index) { 141 if (this.isEmpty()) 142 return null; 143 if (index <= 0 || index > this.size) 144 return null; 145 146 // 查找结点 147 return getNode(index).data; 148 } 149 150 // 查找数据是否存在 151 public boolean contains(Object data) { 152 if (data == null) 153 return false; 154 if (this.isEmpty()) 155 return false; 156 157 // 查找结点 158 if (getNode(data) == null) 159 return false; 160 else 161 return true; 162 } 163 164 // 删除指定数据 165 public boolean remove(Object data) { 166 if (data == null) 167 return false; 168 if (this.isEmpty()) 169 return false; 170 171 // 查找结点 172 Node node = getNode(data); 173 if (node == null) 174 return false; 175 176 // 删除结点 177 removeNode(node); 178 this.size--; // 长度减一 179 return true; 180 } 181 182 // 删除第index个结点 183 public boolean removeIndex(int index) { 184 if (this.isEmpty()) 185 return false; 186 if (index <= 0 || index > this.size) 187 return false; 188 189 // 查找结点 190 Node node = getNode(index); 191 // 删除结点 192 removeNode(node); 193 this.size--; // 长度减一 194 return true; 195 } 196 197 // equals() 198 public boolean equals(Object obj) { 199 if (obj == null) 200 return false; 201 202 // 是DoubleLink类 203 if (obj instanceof DoubleLink) { 204 // 对象下转型为DoubleLink类 205 DoubleLink link = (DoubleLink) obj; 206 207 // 比较长度 208 if (this.size != link.size) 209 return false; 210 211 Node thisNode = this.root.next; 212 Node linkNode = link.root.next; 213 // 比较每个结点的后继的数据域是否相同 214 while (true) { 215 if (thisNode.data == null) // 只有头结点数据域为空 216 break; 217 218 if (!thisNode.data.equals(linkNode.data)) // 结点数据域不相同 219 return false; 220 221 thisNode = thisNode.next; 222 linkNode = linkNode.next; 223 } 224 } 225 return true; 226 } 227 228 // 获得所有数据 229 public Object[] toArray() { 230 if (isEmpty()) 231 return null; 232 233 Object[] datas = new Object[this.size]; 234 int index = 0; // 数组脚标 235 Node node = this.root.prev; // 当前结点 236 while (true) { 237 if (node.data == null) // 只有头结点数据域为空 238 break; 239 datas[index++] = node.data; 240 node = node.prev; 241 } 242 243 return datas; 244 } 245 246 // 打印信息 247 public void print() { 248 if (isEmpty()) 249 System.out.println("空表"); 250 251 else { 252 Node node = this.root.next; 253 while (true) { 254 if (node.data == null) 255 break; 256 System.out.print(node.data + " "); 257 node = node.next; 258 } 259 System.out.println(); 260 } 261 } 262 263 }
TestDoubleLink类
1 package List; 2 3 // 双向链表测试类 4 public class TestDoubleLink { 5 6 public static void main(String[] args) { 7 // TODO Auto-generated method stub 8 9 // 初始化一个双向链表 10 DoubleLink link1 = new DoubleLink(); 11 link1.print(); 12 13 // 添加数据 14 System.out.println("头插法添加10 5 12 null"); 15 System.out.print("添加结果:"+link1.addData(10)+" "); 16 System.out.print(link1.addData(5)+" "); 17 System.out.print(link1.addData(12)+" "); 18 System.out.println(link1.addData(null)); 19 link1.print(); 20 21 // 在指定位置前插入数据 22 System.out.println(" 在第2为前插入一个40,在第4位前插入一个50"); 23 System.out.println("插入结果:"+link1.addData(40, 2)+" "+link1.addData(50,4)); 24 link1.print(); 25 26 // 检查是否指定数据 27 System.out.println(" 检查是否含有数据:50 30"); 28 System.out.println("检查结果:"+link1.contains(50)+" "+link1.contains(30)); 29 link1.print(); 30 31 // 删除指定数据 32 System.out.println(" 删除指定数据:50 0"); 33 System.out.println("删除结果:"+link1.remove(50)+" "+link1.remove(0)); 34 link1.print(); 35 36 // 删除指定位置上的数据 37 System.out.println(" 删除指定位置上的数据:第3位 第10位"); 38 System.out.println("删除结果:"+link1.removeIndex(3)+" "+link1.removeIndex(10)); 39 link1.print(); 40 41 42 // 比较两个链表是否相同 43 DoubleLink link2 = new DoubleLink(); 44 DoubleLink link3 = new DoubleLink(); 45 link2.addData(10); 46 link2.addData(40); 47 link2.addData(12); 48 link3.addData(12); 49 link3.addData(40); 50 link3.addData(10); 51 System.out.println(" 比较两个链表是否相同"); 52 System.out.print("link1:"); 53 link1.print(); 54 System.out.print("link2:"); 55 link2.print(); 56 System.out.print("link3:"); 57 link3.print(); 58 System.out.println("link1和link2: "+link1.equals(link2)+" link1和link3:"+link1.equals(link3)+" link1和null:"+link1.equals(null)); 59 60 } 61 62 }
打印
1 空表 2 头插法添加10 5 12 null 3 添加结果:true true true false 4 12 5 10 5 6 在第2为前插入一个40,在第4位前插入一个50 7 反查反查插入结果:true true 8 12 40 5 50 10 9 10 检查是否含有数据:50 30 11 检查结果:true false 12 12 40 5 50 10 13 14 删除指定数据:50 0 15 删除结果:true false 16 12 40 5 10 17 18 删除指定位置上的数据:第3位 第10位 19 反查删除结果:true false 20 12 40 10 21 22 比较两个链表是否相同 23 link1:12 40 10 24 link2:12 40 10 25 link3:10 40 12 26 link1和link2: true 27 link1和link3:false 28 link1和null:false
总结:1.避免查找错误:先执行查找函数,再改变链表长度。
参考:https://www.cnblogs.com/skywang12345/p/3561803.html
2018-7-20