链表核心的本质意义在于:可变的对象数组;
定义开发链表标准:
interface ILink {
public void add(Object data) ; // 这个方法向链表之中保存对象
public int size() ; // 取得链表的长度
public boolean isEmpty() ; // 判断该链表是否有数据
public Object get(int index) ; // 根据索引取得链表中保存的数据
public boolean contains(Object obj) ;// 查询某个数据是否存在
public void remove(Object obj) ; // 删除不需要的数据
public void set(int index,Object data) ; // 根据索引修改指定数据
public void clean() ; // 清空链表
public Object [] toArray() ; // 变为对象数组后输出
}
1 package cn.demo;
2 class Phone { 3 private String brand ; 4 private double price ; 5 public Phone(String brand,double price) { 6 this.brand = brand ; 7 this.price = price ; 8 } 9 // 无参构造、setter与getter略 10 public String toString() { 11 return "品牌:" + this.brand + ",价格:" + this.price ; 12 } 13 public boolean equals(Object obj) { 14 if (this == obj) { 15 return true ; 16 } 17 if (obj == null) { 18 return false ; 19 } 20 if (!(obj instanceof Phone)) { 21 return false ; 22 } 23 Phone ph = (Phone) obj ; 24 return this.brand.equals(ph.brand) && this.price == ph.price ; 25 } 26 } 27 interface ILink { 28 public void add(Object data) ; // 这个方法向链表之中保存对象 29 public int size() ; // 取得链表的长度 30 public boolean isEmpty() ; // 判断该链表是否有数据 31 public Object get(int index) ; // 根据索引取得链表中保存的数据 32 public boolean contains(Object obj) ;// 查询某个数据是否存在 33 public void remove(Object obj) ; // 删除不需要的数据 34 public void set(int index,Object data) ; // 根据索引修改指定数据 35 public void clean() ; // 清空链表 36 public Object [] toArray() ; // 变为对象数组后输出 37 } 38 class LinkImpl implements ILink { 39 // Node类可以描述出对象保存的先后顺序 40 private class Node { // 这个类用户不需要知道,只有本类使用 41 private Object data ; // 保存数据 42 private Node next ; // 保存下一个节点 43 // 保证每一个Node创建的时候都有要保存的数据 44 public Node(Object data) { 45 this.data = data ; 46 } 47 // 第1次执行:this = LinkImpl.root 48 // 第2次执行:this = LinkImpl.root.next 49 // 第3次执行:this = LinkImpl.root.next.next 50 public void addNode(Node newNode) { // 设置节点关系 51 if (this.next == null) { // 当前节点之后有位置 52 this.next = newNode ; // 保存新节点 53 } else { // 如果没有位置 54 this.next.addNode(newNode) ; 55 } 56 } 57 // 第1次执行:this = LinkImp.root 58 // 第2次执行:this = LinkImp.root.next 59 public Object getNode(int index) { 60 if (LinkImpl.this.foot ++ == index) { 61 return this.data ; 62 } else { 63 return this.next.getNode(index) ; 64 } 65 } 66 // 第1次:this = LinkImpl.root.next,previous = LinkImp.root 67 public void removeNode(Node previous,Object obj) { 68 if (this.data.equals(obj)) { 69 previous.next = this.next ; 70 } else { // 之前已经判断过要删除的数据存在 71 this.next.removeNode(this,obj) ; 72 } 73 } 74 public boolean containsNode(Object data) { 75 if (this.data.equals(data)) { 76 return true ; 77 } else { 78 if (this.next != null) { 79 return this.next.containsNode(data) ; 80 } else { 81 return false ; 82 } 83 } 84 } 85 public void setNode(Object obj,int index) { 86 if (LinkImpl.this.foot ++ == index) { 87 this.data = obj ; 88 } else { 89 this.next.setNode(obj,index) ; 90 } 91 } 92 public void toArrayNode() { 93 LinkImpl.this.retObj [LinkImpl.this.foot ++] = this.data ; 94 if (this.next != null) { 95 this.next.toArrayNode() ; 96 } 97 } 98 } 99 // ******************************* 100 private Node root ; // 表示根节点 101 private int count = 0 ; 102 private int foot = 0 ; // 查找使用 103 private Object retObj [] ; // 返回的对象数组 104 // ************* 覆写接口中的方法 ********** 105 public void add(Object data) { 106 // 1、数据本身不包含有先后的顺序 107 // 需要将数据包装在Node类对象之中,因为Node可以描述先后关系 108 if (data == null) { // 数据为null 109 return ; // 结束调用 110 } 111 // 2、将数据包装在Node类对象之中 112 Node newNode = new Node(data) ; 113 // 3、处理根元素 114 if (this.root == null) { // 现在没有根元素 115 this.root = newNode ; // 将第一个节点保存为根元素 116 } else { 117 this.root.addNode(newNode) ;// 交由Node处理 118 } 119 this.count ++ ; 120 } 121 public int size() { 122 return this.count ; 123 } 124 public boolean isEmpty() { 125 return this.count == 0 && this.root == null ; 126 } 127 public Object get(int index) { 128 if (this.isEmpty()) { // 为空元素 129 return null ; 130 } 131 if (index >= this.count) { // 超过了保存数量 132 return null ; 133 } 134 this.foot = 0 ; 135 return this.root.getNode(index) ; 136 } 137 public boolean contains(Object obj) { 138 if (this.isEmpty()) { 139 return false ; 140 } 141 return this.root.containsNode(obj) ; 142 } 143 public void remove(Object obj) { 144 if (!this.contains(obj)) { // 数据不存在 145 return ; // 结束方法 146 } 147 // 链表里面最关注的是根节点 148 if (this.root.data.equals(obj)) { // 根节点要删除 149 this.root = this.root.next ; // 下一个作为根节点 150 } else { // 根节点判断完了 151 this.root.next.removeNode(this.root,obj) ; 152 } 153 this.count -- ; 154 } 155 public void set(int index,Object data){ 156 this.foot = 0 ; 157 if (this.isEmpty()) { // 为空元素 158 return ; 159 } 160 if (index >= this.count) { // 超过了保存数量 161 return ; 162 } 163 this.root.setNode(data,index) ; 164 } 165 public void clean() { 166 this.root = null ; 167 this.count = 0 ; 168 } 169 public Object [] toArray() { 170 if (this.isEmpty()) { 171 return null ; 172 } 173 this.foot = 0 ; 174 this.retObj = new Object [this.count] ; 175 this.root.toArrayNode() ; 176 return this.retObj ; 177 } 178 } 179 public class TestLink { 180 public static void main(String args[]) { 181 ILink all = new LinkImpl() ; 182 // System.out.println("保存数据个数:" + all.size() + ",是否为空链表:" + all.isEmpty()) ; 183 all.add(new Phone("黑米",19.8)) ; 184 all.add(new Phone("紫米",29.8)) ; 185 Object data [] = all.toArray() ; 186 for (int x = 0 ; x < data.length ; x ++) { 187 System.out.println(data[x]) ; 188 } 189 // 190 all.set(0,new Phone("绿米",39.8)) ; 191 all.clean() ; 192 System.out.println(all.get(0)) ; 193 all.remove(new Phone("黑米",19.8)) ; 194 System.out.println("保存数据个数:" + all.size() + ",是否为空链表:" + all.isEmpty()) ; 195 System.out.println(all.get(0)) ; 196 System.out.println(all.get(2)) ; 197 System.out.println(all.contains(new Phone("黑米",19.8))) ; 198 System.out.println(all.contains(new Phone("大米",19.8))) ; 199 } 200 }
结果:
品牌:黑米,价格:19.8
品牌:紫米,价格:29.8
null
保存数据个数:0,是否为空链表:true
null
null
false
false
总结:必须知道链表接口中的每一个方法,尤其是contains()和remove()两个方法需要equals()支持。