类的结构
接口: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 16 public boolean isEmpty(); 17 18 19 public boolean contains(Object o); 20 21 22 public boolean add(E e); 23 24 public void add(int index, E element); 25 26 public E remove(int index); 27 28 public E get(int index); 29 30 31 public E set(int index, E element); 32 33 34 public int indexOf(Object o); 35 36 public void clear(); 37 38 String toString(); 39 40 41 // public boolean remove(Object o); 42 43 44 // public Iterator<E> iterator(); 45 46 47 // public Object[] toArray(); 48 49 50 // public <T> T[] toArray(T[] a); 51 52 53 // public boolean containsAll(Collection<?> c); 54 // 55 // 56 // public boolean addAll(Collection<? extends E> c); 57 // 58 // 59 // public boolean addAll(int index, Collection<? extends E> c) ; 60 // 61 // 62 // public boolean removeAll(Collection<?> c); 63 // 64 // 65 // public boolean retainAll(Collection<?> c); 66 67 68 // public int lastIndexOf(Object o); 69 // 70 // 71 // public ListIterator<E> listIterator(); 72 // 73 // 74 // public ListIterator<E> listIterator(int index); 75 // 76 // 77 // public List<E> subList(int fromIndex, int toIndex); 78 79 }
抽象类: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 }
自定义(单链表)集合类:
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 16 private static class Node<E>{ 17 E element; 18 Node<E> next; 19 Node(E element,Node<E> next){ 20 this.element = element; 21 this.next = next; 22 } 23 } 24 25 26 27 /** 28 * 在指定索引index处插入指定元素 29 * @param index 注意:index >= 0 && index <= size (是可以插入到最后一个元素的下一个位置的) 30 * @param element 31 */ 32 @Override 33 public void add(int index, E element) { 34 checkPositionIndex(index);//判断index >=0 && index <= size 35 if (index == 0) {//这里不管first是否为null,都是没有问题的 36 //如果最开始的first为null,则插入的节点为node(element,null),被first指向 37 //如果最开始的first不为null,则插入的节点为node(element,first),除了被first指向,它还指向最开始的那个first 38 first = new Node(element, first); 39 } else {//插入位置索引不是0 40 Node<E> pre = node(index - 1);//前一个节点 41 Node<E> next = pre.next;//后一个节点 42 pre.next = new Node(element,next);//前一个节点指向插入的节点,这个插入的节点指向后一个节点 43 } 44 size++; 45 } 46 47 48 private void checkPositionIndex(int index) { 49 if (!isPositionIndex(index)) { 50 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); 51 } 52 } 53 54 private boolean isPositionIndex(int index) { 55 return index >= 0 && index <= size; 56 } 57 58 /** 59 * 移除集合中指定索引的元素,并返回这个元素 60 * @param index 61 * @return 62 */ 63 @Override 64 public E remove(int index) { 65 checkElementIndex(index); 66 Node<E> oldNode; 67 if (index==0) { 68 oldNode = first; 69 first = first.next; 70 size--; 71 return oldNode.element; 72 } 73 //先从一般的规律入手,写下来,再看特殊情况, 74 //如果index=0,那么index-1就为负数,肯定是不行的,所以才有上面if (index==0) 的情况 75 Node<E> pre = node(index - 1); 76 oldNode = pre.next; 77 pre.next = oldNode.next; 78 size--; 79 return oldNode.element; 80 } 81 82 /** 83 * 获取指定索引(节点)处的元素 84 * 因为增删改都是基于先找到元素,所以这个方法最先实现比较好 85 * @param index 86 * @return 87 */ 88 @Override 89 public E get(int index) { 90 checkElementIndex(index); 91 return node(index).element; 92 93 } 94 95 /** 96 * 检查指定索引,如果集合中不存在这个指定索引,则抛出异常 97 * @param index 98 */ 99 private void checkElementIndex(int index) { 100 if (!isElementIndex(index)) { 101 throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size); 102 } 103 } 104 105 /** 106 * 找到指定索引index对应的Node节点 107 * @param index 108 * @return 109 */ 110 private Node<E> node(int index) { 111 //获取集合第一个元素first 112 Node<E> x = first; 113 //通过x.next,循环遍历找到指定索引index对应的Node节点 114 for (int i = 0; i < index; i++) { 115 x = x.next; 116 } 117 return x; 118 } 119 120 /** 121 * 判断集合中是否存在指定索引 122 * @param index 123 * @return 124 */ 125 private boolean isElementIndex(int index) { 126 return index >= 0 && index < size; 127 } 128 129 130 /** 131 * 将指定索引处的元素替换为指定的元素 132 * @param index 指定的索引 133 * @param element 将要替换到指定索引处的元素 134 * @return 返回指定索引处被替换的元素 135 */ 136 @Override 137 public E set(int index, E element) { 138 checkElementIndex(index); 139 Node<E> node = node(index); 140 E oldEle = node.element; 141 node.element = element; 142 return oldEle; 143 } 144 145 /** 146 * 查找第一次出现指定元素o的索引位置 147 * @param o 148 * @return 如果有,返回o在集合中的索引;如果没有,返回-1 149 */ 150 @Override 151 public int indexOf(Object o) { 152 int index = 0; 153 if (o == null) { 154 //多去理解这种遍历思维 155 for (Node<E> x = first; x != null; x = x.next) { 156 if (x.element == o) { 157 return index; 158 } 159 //还有这种返回索引的思维也要多学习 160 index++; 161 } 162 } else { 163 for (Node<E> x = first; x != null; x = x.next) { 164 if (o.equals(x.element)) { 165 return index; 166 } 167 index++; 168 } 169 } 170 return -1; 171 } 172 173 /** 174 * 清空集合的所有元素 175 * 176 * 可达性算法:判断对象是否是一个垃圾的标准 177 * 选取一个节点,作为GC ROOTS顶点,其他对象或者引用去指向这个GC ROOTS顶点,如果这些对象 178 * 能够到达这个GC ROOTS顶点,那么这些对象不是垃圾,反之就是。 179 * 180 */ 181 @Override 182 public void clear() { 183 size = 0; 184 first = null; 185 } 186 187 @Override 188 public String toString() { 189 if (size == 0) { 190 return "[]"; 191 } 192 StringBuilder sb= new StringBuilder(); 193 sb.append('['); 194 for( Node<E> x = first;x!=null;x=x.next){ 195 sb.append(x.element); 196 if (x.next == null) { 197 return sb.append(']').toString(); 198 } 199 sb.append(',').append(' '); 200 } 201 return sb.toString(); 202 } 203 }