自定义(双链表)集合类

包结构

 

 

 

MyList 接口 

 1 package day2_19.inter;
 2 
 3 /**
 4  * 将arryList 和 linkedList 共性的方法进行抽取 --->保证体系的完整性
 5  *
 6  * @Author Tianhao
 7  * @create 2021-02-19-17:26
 8  */
 9 
10 public interface MyList<E>{
11 
12 
13     public int size();
14 
15     public boolean isEmpty();
16     
17     public boolean contains(Object o);
18 
19     public boolean add(E e);
20 
21     public void add(int index, E element);
22 
23     public E remove(int index);
24 
25     public E get(int index);
26     
27     public E set(int index, E element);
28     
29     public int indexOf(Object o);
30 
31     public void clear();
32 
33     String toString();
34 
35 }

 


MyAbstractList 抽象类
 1 package day2_19.abstractClass;
 2 
 3 import day2_19.inter.MyList;
 4 
 5 /**
 6  *
 7  * 用于实现arryList 和 linkedList中那些相同的方法
 8  *
 9  * @Author Tianhao
10  * @create 2021-02-19-17:46
11  */
12 
13 public abstract class MyAbstractList<E> implements MyList<E> {
14     protected int size;
15 
16     /**
17      * 获取元素个数
18      * @return 元素个数
19      */
20     @Override
21     public int size() {
22         return size;
23     }
24 
25     /**
26      * 判断集合是否为空
27      * @return
28      */
29     @Override
30     public boolean isEmpty() {
31         return size == 0;
32     }
33 
34     /**
35      * 判断集合是否包含指定元素
36      * indexOf(Object o):寻找对应的元素,如果找到了返回元素的索引,如果没有找到返回 -1
37      * @param o
38      * @return
39      */
40     @Override
41     public boolean contains(Object o) {
42         return indexOf(o) != -1;
43     }
44 
45 
46     /**
47      * 在集合的最后添加一个元素,也就是在索引为size处添加一个元素
48      * @param e
49      * @return
50      */
51     @Override
52     public boolean add(E e) {
53         add(size,e);
54         return true;
55     }
56 }

 

MyLinkedList 类
  1 package day2_19.linked;
  2 
  3 import day2_19.abstractClass.MyAbstractList;
  4 
  5 /**
  6  *
  7  * 自定义(单链表)集合类
  8  *
  9  * @Author Tianhao
 10  * @create 2021-02-19-18:01
 11  */
 12 public class MyLinkedList<E> extends MyAbstractList<E> {
 13 
 14     private Node<E> first;
 15     private Node<E> last;
 16 
 17     private static class Node<E>{
 18         E element;
 19         Node<E> next;
 20         Node<E> pre;
 21         Node(Node<E> pre,E element,Node<E> next){
 22             this.element = element;
 23             this.next = next;
 24             this.pre = pre;
 25         }
 26     }
 27 
 28 
 29 
 30     /**
 31      * 在指定索引index处插入指定元素
 32      * @param index 注意:index >= 0 && index <= size (是可以插入到最后一个元素的下一个位置的)
 33      * @param element
 34      */
 35     @Override
 36     public void add(int index, E element) {
 37         checkPositionIndex(index);//判断index >=0 && index <= size
 38 
 39         //方法一:常规思维
 40 //        if (index == 0) {//这里不管first是否为null,都是没有问题的
 41 //            //如果最开始的first为null,则插入的节点为node(element,null),被first指向
 42 //            //如果最开始的first不为null,则插入的节点为node(element,first),除了被first指向,它还指向最开始的那个first
 43 //            first = new Node(element, first);
 44 //        } else {//插入位置索引不是0
 45 //            Node<E> pre = node(index - 1);//前一个节点
 46 //            Node<E> next = pre.next;//后一个节点
 47 //            pre.next = new Node(element,next);//前一个节点指向插入的节点,这个插入的节点指向后一个节点
 48 //        }
 49 //        size++;
 50 
 51         //方法二:代码简化
 52         //思路:获得指定的index的节点 2.前一个节点的获取 3.构建要插入的节点 4.改变1和2的指向
 53         if (index == size) {//涉及到last,包含两种情况:1.原来有元素的时候,新元素添加到末尾  2.原来没有元素的时候
 54             linkLast(element);
 55         } else {//不涉及到last
 56             linkBefore(element,index);
 57         }
 58         size++;
 59 
 60 
 61 
 62     }
 63 
 64     private void linkLast(E element) {
 65         //方法一:常规思维
 66 //        Node newNode;
 67 //        if (size == 0) {//原来没有元素的时候
 68 //            //1.构建要插入的节点newNode,完成它的指向关系
 69 //            newNode = new Node(null, element, null);
 70 //            //2.first指向新节点
 71 //            first = newNode;
 72 //        } else {//原来有元素的时候,新元素添加到末尾
 73 //            //1.拿到原来的最后一个节点
 74 //            Node<E> pre = last;
 75 //            //2.构建要插入的节点newNode,完成它的指向关系
 76 //            newNode = new Node(pre, element, null);
 77 //            //3.将原来的最后一个节点指向新节点
 78 //            pre.next = newNode;
 79 //        }
 80 //        //最后将last指向新节点
 81 //        last = newNode;
 82 
 83         //方法二:代码简化
 84         Node newNode;
 85         //1.拿到last
 86         Node<E> pre = last;
 87         //2.构建要插入的节点newNode,完成它的指向关系
 88         newNode = new Node(pre, element, null);
 89         //3.将last指向新节点
 90         last = newNode;
 91         if (pre == null) {//原来没有元素的时候
 92             //first指向新节点
 93             first = newNode;
 94         } else {//原来有元素的时候,新元素添加到末尾
 95             //将原来的最后一个节点指向新节点
 96             pre.next = newNode;
 97         }
 98 
 99 
100     }
101 
102     private void linkBefore(E element,int index) {
103         //1.获取索引index处的节点
104         Node<E> next = node(index);
105         //2.获取索引(index-1)处的节点
106         Node<E> pre = next.pre;
107         //3.构建要插入的节点newNode,完成它的指向关系
108         Node<E> newNode = new Node(pre, element, next);
109         //4.索引index处的节点指向新节点
110         next.pre = newNode;
111 
112         if (pre == null) { //索引index==0时
113             //first指向新节点
114             first = newNode;
115         } else {
116             //索引(index-1)处的节点指向新节点
117             pre.next = newNode; //为了防止此行空指针异常,所以必须考虑pre === null的情况
118         }
119     }
120 
121 
122     private void checkPositionIndex(int index) {
123         if (!isPositionIndex(index)) {
124             throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
125         }
126     }
127 
128     private boolean isPositionIndex(int index) {
129         return index >= 0 && index <= size;
130     }
131 
132     /**
133      * 移除集合中指定索引的元素,并返回这个元素
134      * @param index
135      * @return
136      */
137     @Override
138     public E remove(int index) {
139         checkElementIndex(index);
140         //先从一般的规律入手,写下来,再看特殊情况,
141         Node<E> node = node(index);
142         final E element = node.element;
143         final Node<E> pre = node.pre;
144         final Node<E> next = node.next;
145         if (pre == null) { //index == 0
146             first = next;
147         } else {
148             pre.next = next;
149             //将要移除节点的pre设置为null
150             node.pre = null;
151         }
152         if (next == null) {
153             last = pre;
154 
155         } else {
156             next.pre = pre;
157             //将要移除节点的next设置为null
158             node.next = null;
159         }
160         //将要移除节点的element设置为null
161         node.element = null;
162         size--;
163         return element;
164     }
165 
166 
167 
168     /**
169      * 获取指定索引(节点)处的元素
170      * 因为增删改都是基于先找到元素,所以这个方法最先实现比较好
171      * @param index
172      * @return
173      */
174     @Override
175     public E get(int index) {
176         checkElementIndex(index);
177         return node(index).element;
178 
179     }
180 
181     /**
182      * 检查指定索引,如果集合中不存在这个指定索引,则抛出异常
183      * @param index
184      */
185     private void checkElementIndex(int index) {
186         if (!isElementIndex(index)) {
187             throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size);
188         }
189     }
190 
191     /**
192      * 找到指定索引index对应的Node节点
193      * @param index
194      * @return
195      */
196     private Node<E> node(int index) {
197         //获取集合第一个元素first
198         Node<E> x = first;
199         //先去判断要查找的index是靠近头还是靠近尾,如果靠近头,从头开始找;如果靠近尾,从尾开始找
200         //如果index小于size的二分之一,则靠近头
201         //size>>1:向右移动一位,就除以2
202         if (index < (size >> 1)) {
203             for (int i = 0; i < index; i++) {
204                 x = x.next;
205             }
206         } else {
207             x = last;
208             for (int i = size-1; i > index; i--) {
209                 x = x.pre;
210             }
211         }
212 
213         return x;
214     }
215 
216     /**
217      * 判断集合中是否存在指定索引
218      * @param index
219      * @return
220      */
221     private boolean isElementIndex(int index) {
222         return index >= 0 && index < size;
223     }
224 
225 
226     /**
227      * 将指定索引处的元素替换为指定的元素
228      * @param index 指定的索引
229      * @param element 将要替换到指定索引处的元素
230      * @return 返回指定索引处被替换的元素
231      */
232     @Override
233     public E set(int index, E element) {
234         checkElementIndex(index);
235         Node<E> node = node(index);
236         E oldEle = node.element;
237         node.element = element;
238         return oldEle;
239     }
240 
241     /**
242      * 查找第一次出现指定元素o的索引位置
243      * @param o
244      * @return 如果有,返回o在集合中的索引;如果没有,返回-1
245      */
246     @Override
247     public int indexOf(Object o) {
248         int index = 0;
249         if (o == null) {
250             //多去理解这种遍历思维
251             for (Node<E> x = first; x != null; x = x.next) {
252                 if (x.element == o) {
253                     return index;
254                 }
255                 //还有这种返回索引的思维也要多学习
256                 index++;
257             }
258         } else {
259             for (Node<E> x = first; x != null; x = x.next) {
260                 if (o.equals(x.element)) {
261                     return index;
262                 }
263                 index++;
264             }
265         }
266         return -1;
267     }
268 
269     /**
270      * 清空集合的所有元素
271      *
272      * 可达性算法:判断对象是否是一个垃圾的标准
273      *  选取一个节点,作为GC ROOTS顶点,其他对象或者引用去指向这个GC ROOTS顶点,如果这些对象
274      *  能够到达这个GC ROOTS顶点,那么这些对象不是垃圾,反之就是。
275      *
276      */
277     @Override
278     public void clear() {
279         //遍历所有的节点,只要不为null,就将其pre,next,element都设置为null
280         for (Node<E> x = first; x != null;) {
281             Node<E> next = x.next;
282             x.pre = null;
283             x.next = null;
284             x.element = null;
285             x = next;
286         }
287         size = 0;
288         first = null;
289         last = null;
290     }
291 
292     @Override
293     public String toString() {
294         if (size == 0) {
295             return "[]";
296         }
297         StringBuilder sb= new StringBuilder().append('[');
298         for( Node<E> x = first;x!=null;x=x.next){
299             sb.append(x.element);
300             if (x.next == null) {
301                 return sb.append(']').toString();
302             }
303             sb.append(',').append(' ');
304         }
305         return sb.toString();
306     }
307 }
posted @ 2021-02-28 22:50  dog_IT  阅读(72)  评论(0编辑  收藏  举报