一、定义MyList接口,包含列表常见方法:
1 import java.util.Iterator; 2 3 /** 4 * 线性表(列表)的接口定义 5 */ 6 public interface MyList<T> extends Iterator<T> { 7 8 /** 新增一个元素 */ 9 void add(T element); 10 11 /** 删除相同元素 */ 12 void delete(T element); 13 14 /** 根据索引删除元素 */ 15 void delete(int index); 16 17 /** 18 * 将指定索引位置的元素替换成新元素 19 * 20 * @param index 21 * @param newElement 22 */ 23 void update(int index, T newElement); 24 25 /** 26 * 当前列表中是否含有target这个元素 27 * 28 * @param target 29 * @return 30 */ 31 boolean contains(T target); 32 33 /** 34 * 返回指定索引处的元素 35 * 36 * @param index 37 * @return 38 */ 39 T at(int index); 40 41 /** 42 * 查找element的索引,如果没有返回-1 43 * 44 * @param element 45 * @return 46 */ 47 int indexOf(T element); 48 49 }
二、实现ArrayList类:
1 /** 2 * 用顺序存储(数组)方式来实现列表 3 */ 4 public class MyArrayList<T> implements MyList<T> { 5 private T[] elements;// 真正存储元素的底层结构 6 7 private int size = 0;// 元素个数 8 9 private int capacity = 10;// 容量 10 11 public MyArrayList(int capacity) { 12 this.capacity = capacity; 13 elements = (T[]) new Object[capacity]; 14 } 15 16 public MyArrayList() { 17 elements = (T[]) new Object[capacity]; 18 } 19 20 @Override 21 public void add(T element) { 22 if (size == capacity) {// 扩容 23 capacity *= 2;// 增加一倍的容量 24 T[] newArr = (T[]) new Object[capacity];// 新建一个数组 25 for (int i = 0; i < size; i++) { 26 newArr[i] = elements[i]; 27 } 28 elements = newArr;// 把旧的那个柜子扔掉 29 } 30 elements[size++] = element; 31 } 32 33 @Override 34 public void delete(T element) { 35 int index = indexOf(element); 36 if (index >= 0) { 37 delete(index); 38 } 39 } 40 41 @Override 42 public void delete(int index) { 43 // 重新调整空间 44 for (int i = index; i < size - 1; i++) { 45 elements[i] = elements[i + 1]; 46 } 47 elements[size - 1] = null; 48 size--; 49 } 50 51 @Override 52 public void update(int index, T newElement) { 53 elements[index] = newElement; 54 } 55 56 @Override 57 public boolean contains(T target) { 58 return indexOf(target) >= 0; 59 } 60 61 @Override 62 public T at(int index) { 63 return elements[index]; 64 } 65 66 @Override 67 public int indexOf(T element) { 68 for (int i = 0; i < size; i++) { 69 if (elements[i].equals(element)) { 70 return i; 71 } 72 } 73 return -1; 74 } 75 76 @Override 77 public String toString() { 78 StringBuilder sb = new StringBuilder("["); 79 for (int i = 0; i < size; i++) { 80 sb.append(elements[i] + (i == size - 1 ? "" : " , ")); 81 } 82 sb.append("]"); 83 return sb.toString(); 84 } 85 86 // 87 @Override 88 public boolean hasNext() { 89 return false; 90 } 91 92 @Override 93 public T next() { 94 return null; 95 } 96 }
三、链表结点类:
1 /*节点*/ 2 public class ListNode<T> { 3 T data; 4 ListNode<T> pre; 5 ListNode<T> next; // next 实际存的是下一个节点 重要理解 6 7 public ListNode(T data) { 8 this.data = data; 9 } 10 11 public T getData() { 12 return data; 13 } 14 15 public ListNode<T> getPre() { 16 return pre; 17 } 18 19 public void setNext(ListNode<T> next) { 20 this.next = next; 21 } 22 23 public void setPre(ListNode<T> pre) { 24 this.pre = pre; 25 } 26 27 public ListNode<T> getNext() { 28 return next; 29 } 30 }
四、单链表实现:
public class SingleLinkedList<T> implements MyList<T> { private ListNode<T> first; // 头节点 head private ListNode<T> last; // 尾节点 private int size; @Override public void add(T element) { if (first == null) { first = new ListNode(element); last = first; } else { last.next = new ListNode(element); // next 实际存的是下一个节点 重要理解 last = last.next; } size++; } @Override public void delete(T element) { ListNode p = first; ListNode pre = null; while (p != null) { if (p.data.equals(element)) { if (p == first) first = first.next; else pre.next = p.next; size--; break;// 注意这里 } pre = p; p = p.next; } } // 链表删除 // 参数为索引 @Override public void delete(int index) { if (index < 0 || index >= size) { return;// 啥也不干 } int i = 0;// 指针指向的节点的索引 ListNode p = first; ListNode pre = null; while (p != null) { if (i == index) { if (p == first) first = first.next; else pre.next = p.next; break;// 注意这里 } pre = p; p = p.next; i++; } size--; } @Override public void update(int index, T newElement) { if (index < 0 || index >= size) { return;// 啥也不干 } int i = 0;// 指针指向的节点的索引 ListNode p = first; while (p != null) { if (i == index) { p.data = newElement; } p = p.next; i++; } } @Override public boolean contains(T target) { ListNode p = first; while (p != null) { if (p.data.equals(target)) { return true; } p = p.next; } return false; } // 返回索引所在的data @Override public T at(int index) { if (index < 0 || index >= size) { return null; } int i = 0;// 指针指向的节点的索引 ListNode<T> p = first; while (p != null) { if (i == index) { return p.data; } p = p.next; i++; } return null; } @Override public int indexOf(T element) { int i = 0;// 指针指向的节点的索引 ListNode p = first; while (p != null) { if (p.data.equals(element)) { return i; } p = p.next; i++; } return -1; } @Override public String toString() { StringBuilder sb = new StringBuilder("["); ListNode p = first; while (p != null) { sb.append(p.data); if (p.next != null) sb.append(","); p = p.next; } sb.append("]"); return sb.toString(); } @Override public boolean hasNext() { return false; } @Override public T next() { return null; } }
五、双链表实现:
1 import java.util.Iterator; 2 3 public class DoubleLinkedList<T> implements MyList<T> { 4 5 // 多了两个没有数据的头节点和尾节点 哑元 6 protected ListNode<T> first = new ListNode(null); 7 protected ListNode<T> last = new ListNode(null); 8 protected int size; 9 10 public int getSize() { 11 return size; 12 } 13 14 public DoubleLinkedList() { 15 first.next = last; 16 last.pre = first; 17 } 18 19 @Override 20 public void add(T element) { 21 ListNode<T> newNode = new ListNode(element); 22 last.pre.next = newNode; 23 newNode.next = last; 24 newNode.pre = last.pre; 25 last.pre = newNode; 26 size++; 27 } 28 29 @Override 30 public void delete(T element) { 31 ListNode<T> p = first.next; 32 while (p != last) { 33 if (p.data.equals(element)) { 34 p.pre.next = p.next; 35 p.next.pre = p.pre; 36 p.next = null; 37 p.pre = null; 38 size--; 39 break; 40 } 41 p = p.next; 42 } 43 } 44 45 @Override 46 public void delete(int index) { 47 if (index < 0 || index >= size) { 48 return;// 啥也不干 49 } 50 int i = 0;// 指针指向的节点的索引 51 ListNode p = first.next; 52 53 while (p != last) { 54 if (i == index) { 55 p.pre.next = p.next; 56 p.next.pre = p.pre; 57 p.next = null; 58 p.pre = null; 59 size--; 60 break;// 注意这里 61 } 62 p = p.next; 63 i++; 64 } 65 } 66 67 @Override 68 public void update(int index, T newElement) { 69 if (index < 0 || index >= size) { 70 return;// 啥也不干 71 } 72 int i = 0;// 指针指向的节点的索引 73 ListNode p = first.next; 74 75 while (p != last) { 76 if (i == index) { 77 p.data = newElement; 78 } 79 p = p.next; 80 i++; 81 } 82 } 83 84 @Override 85 public boolean contains(T target) { 86 ListNode p = first.next; 87 while (p != last) { 88 if (p.data.equals(target)) { 89 return true; 90 } 91 p = p.next; 92 } 93 return false; 94 } 95 96 @Override 97 public T at(int index) { 98 if (index < 0 || index >= size) { 99 return null; 100 } 101 int i = 0;// 指针指向的节点的索引 102 ListNode<T> p = first.next; 103 104 while (p != last) { 105 if (i == index) { 106 return p.data; 107 } 108 p = p.next; 109 i++; 110 } 111 return null; 112 } 113 114 @Override 115 public int indexOf(T element) { 116 int i = 0;// 指针指向的节点的索引 117 ListNode<T> p = first.next; 118 119 while (p != last) { 120 if (p.data.equals(element)) { 121 return i; 122 } 123 p = p.next; 124 i++; 125 } 126 return -1; 127 } 128 129 @Override 130 public String toString() { 131 StringBuilder sb = new StringBuilder("["); 132 ListNode p = first.next; 133 while (p != last) { 134 sb.append(p.data); 135 if (p.next != last) 136 sb.append(","); 137 p = p.next; 138 } 139 sb.append("]"); 140 return sb.toString(); 141 } 142 143 144 // 实现迭代器 MyList 继承Iterator<T>这个接口 145 private ListNode now = first; 146 147 @Override 148 public boolean hasNext() { 149 return now.next != last; 150 } 151 152 @Override 153 public T next() { 154 ListNode<T> next = now.next; 155 now = now.next; 156 return next.data; 157 } 158 }
六、Java ListApi的基本使用:
1 import java.util.*; 2 3 public class ListApiDemo { 4 public static void main(String[] args) { 5 List<String> list = new ArrayList<>(); 6 list = new LinkedList<>(); 7 list.add("adnda"); 8 list.add("xyz"); 9 list.add("def"); 10 list.remove(""); 11 // ...... 12 13 Collections.sort(list); 14 15 System.out.println(list); 16 List<Student> list1 = new ArrayList<>(); 17 list1.add(new Student("zhangsan", 10)); 18 list1.add(new Student("lsii", 20)); 19 list1.add(new Student("wangwu", 40)); 20 list1.add(new Student("wangsu", 30)); 21 22 Collections.sort(list1, (o1, o2) -> { 23 return o1.getAge() - o2.getAge(); 24 }); 25 26 System.out.println(list1); 27 28 for (int i = 0; i < list1.size(); i++) { 29 System.out.println(list1.get(i)); 30 } 31 32 System.out.println("==============="); 33 for (Student stu : list1) { 34 System.out.println(stu); 35 } 36 System.out.println("++++++++++++++++++++"); 37 Iterator<Student> iterator = list1.iterator(); 38 while (iterator.hasNext()) { 39 System.out.println(iterator.next()); 40 } 41 } 42 } 43 class Student{ 44 String name; 45 int age; 46 public Student(String name, int age) { 47 super(); 48 this.name = name; 49 this.age = age; 50 } 51 public int getAge() { 52 return age; 53 } 54 public void setAge(int age) { 55 this.age = age; 56 } 57 58 }
七、ArrayList和LinkedList总结:
1、ArrayList和LinkedList都是实现了List接口的容器类,用于存储一系列的对象引用。他们都可以对元素的增删改查进行操作。
2、ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
3、对ArrayList和LinkedList的空间复杂度而言,对 ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Node对象。ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间 。
4、对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。 ArrayList可以根据索引直接算出地址。
5、在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
6、对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。对于查找和修改操作,如果按照索引查找和修改,ArrayList优于LinedList,如果按照内容来进行查找和修改,ArrayList和LinedList所花费的时间差不多。
7、LinkedList不支持高效的随机元素访问。 比如二分查找就是才有的随机策略,就不适合采用LinkedList,适合ArrayList。
可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中 间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。 所以,如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是对其它指定位置的插入、删除操作,最好选择LinkedList。
注意:next 实际存的是下一个节点 个人重要理解。