public class MyLinkedList { private class Node{ //定义节点 ,利用私有内部类的排他性 Object data; Node next; Node pre; public Node(){ } public Node(Object data,Node next, Node pre){ this.data = data; this.next = next; this.pre = pre; } } private Node head;//定义头节点 private int size;//定义链表长度 /** * 构造一个空列表 * */ public MyLinkedList() { head = new Node();//空头结点,来区分首部和尾部 head.next = head.pre = head; //head.next = head; //size = 0; } /** * 构造一个包含指定 myList 中的元素的列表,这些元素按其 myList 的迭代器返回的顺序排列。 * @param myList 要将其元素放入此列表的集合 * @exception 如果指定的集合为null,则抛出空指异常 * */ public MyLinkedList(MyLinkedList myList){ this();//调用无参构造器 /* if(myList == null){ throw new NullPointerException(); }*/ addAll(this.size, myList); } /** * 在此列表中指定的位置插入指定的元素。移动当前在该位置处的元素(如果有),所有后续元素都向右移(在其索引中添加 1)。 * @param index - 要在其中插入指定元素的索引 * @param element - 要插入的元素 * @exception 如果索引超出范围 (index < 0 || index > size()) - 抛出IndexOutOfBoundsException异常 * */ public void add(int index, Object data){ cheakIndexException(index, 0); add(findIndexNode(index), data); } /** * 在链表中添加节点的方法 * @param node * @param data * @return true-添加成功,false-添加失败 * */ private void add(Node node, Object data) { //新建一个节点,新节点的next指向node,新节点的last指向node的last //完成指向过程node.pre←newNode→node Node newNode = new Node(data, node, node.pre); //维持双向链表的指向,将node的last节点的next指向新节点,完成指向过程node.pre→newNode node.pre.next = newNode; //node节点的前一个节点指向新节点,完成指向过程newNode←node node.pre = newNode; //上面两行代码不能颠倒,否则node的前一个节点会被覆盖成新节点,会丢失node原来的前一个节点的next指向 //上述代码完成了在node节点和node前一个节点之间加入一个新节点,并维护了双向关系 this.size++; //return true; } /** * 添加指定 myList 中的所有元素到此列表的结尾,顺序是指定 myList 的迭代器返回这些元素的顺序。如果指定的 myList 在操作过程中被修改,则此操作的行为是不确定的。(注意,如果指定 myList 就是此列表并且非空,则此操作的行为是不确定的。) * @param myList-链表 * @return true-表示添加成功 * @param false-表示添加失败 * */ public boolean addAll(MyLinkedList myList){ return addAll(this.size, myList); } /** * 在指定index位置添加myList里的所有元素 * @param index-添加集合的位置 * @param myList-添加的集合 * @exception IndexOutOfBoundsException - 如果索引超出范围 (index < 0 || index > size()) * @exception NullPointerException - 如果指定的 myList为 null * @return true-插入成功 * @return false-插入失败 * */ public boolean addAll(int index, MyLinkedList myList){ cheakIndexException(index, 0); int oldSize = size; Node node = index == this.size ? this.head : findIndexNode(index); Node otherNode = myList.head.next; while(otherNode != myList.head){ add(node, otherNode.data); otherNode = otherNode.next; } //this.size += myList.size; return oldSize != size; } /** * 把元素插在链表首部 * @param - e 要插入的元素 * */ public void addFirst(Object e){ add(this.head.next, e); } /** * 将指定元素添加到此列表的结尾。 * @param - e 要插入的元素 * */ public void addLast(Object e){ add(this.head, e); } /** * 从此列表中移除所有元素。 * */ public void clear(){ Node node = head.next; //将每一个节点的双向指向都清空,这样每个节点都没有被引用,可以方便垃圾回收器回收内存 while(node != head){ Node tmp = node.next; this.remove(node); node = tmp; } //清空head的双向指向null //this.head.next = this.head.pre = this.head; //this.size = 0; } /** * 删除一个节点的方法 * */ private void remove(Node node){ //node的前一个节点next指向node的下一个节点 //node的下一个节点last指向node的前一个节点 //A→node←B改成A→←B node.pre.next = node.next; node.next.pre = node.pre; //node的前后指向null //A←node→B改成null←node→null node.pre = node.next = null; //Object data = node.data; node.data = null; size--; //return data; } /** * 从此列表中移除首次出现的指定元素(如果存在) * @param e-要删除的data * @return true-删除成功 * @return false-删除失败 * */ public boolean remove(Object e){ Node node = head.next; while(node != head) { if(e==null ? node.data==null : e.equals(node.data)){ remove(node); return true; } node = node.next; } return false; } /** * 移除此列表中指定位置处的元素。 * @param index-下标 * @return data-值 * */ public Object remove(int index){ cheakIndexException(index, 1); Node node = findIndexNode(index); Object data = node.data; remove(node); return data; } /** * 删除链表的首部 * @exception NoSuchElementException - 如果此列表为空 * @return 返回被删除的元素 * */ public Object removeFirst(){ cheakNoSuchException(); Node node = this.head.next; Object data = node.data; remove(node); return data; } /** * 删除链表的尾部 * @exception NoSuchElementException - 如果此列表为空 * @return 返回被删除的元素 * */ public Object removeLast(){ cheakNoSuchException(); Node node = this.head.pre; Object data = node.data; remove(node); return data; } /** * 返回此列表中指定位置处的元素 * @param index-要返回的元素的索引 * @return 列表中指定位置的元素 * */ public Object get(int index){ cheakIndexException(index, 1); return findIndexNode(index).data; } /** * 返回此列表中首位的元素 * @return 列表中位于首位的元素 * */ public Object getFirst(){ cheakNoSuchException(); return head.next.data; } /** * 返回此列表中尾部的元素 * @return 列表中位于尾部的元素 * */ public Object getLast(){ cheakNoSuchException(); return head.pre.data; } /** * 将此列表中指定位置的元素替换为指定的元素。 * @param index - 要替换的元素的索引 * @param element - 要在指定位置存储的元素 * @return 以前在指定位置的元素 * */ public Object set(int index, Object element){ cheakIndexException(index, 1); Node node = findIndexNode(index); Object temp = node.data; node.data = element; return temp; } /** * 如果此列表包含指定元素,则返回 true。更确切地讲,当且仅当此列表包含至少一个满足 (o==null ? e==null : o.equals(e)) 的元素 e 时返回 true。 * @return 表示包含 * @return 表示不包含 * */ public boolean contains(Object e) { return indexOf(e) != -1; } /** * 返回此列表中首次出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。更确切地讲,返回满足 (o==null ? get(i)==null : o.equals(get(i))) 的最低索引 i;如果没有此索引,则返回 -1。 * @return -1 - 没有找到该元素 * @return k - 元素的索引 * */ public int indexOf(Object e){ int k = 0; Node node = head.next; while(node != head) { if(e==null ? node.data==null : e.equals(node.data)){ return k; } k++; } return -1; } /** * 返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。更确切地讲,返回满足 (o==null ? get(i)==null : o.equals(get(i))) 的最高索引 i;如果没有此索引,则返回 -1。 * @return -1 - 没有找到该元素 * @return k - 元素的索引 * */ public int lastIndexOf(Object e){ Node node = head.pre; int k = size - 1; while(node != head) { if(e==null ? node.data==null : e.equals(node.data)){ return k; } k--; } return -1; } /** * 检查数组下标越界的方法 * @param index-传入的下标 * @exception IndexOutOfBoundsException - 如果索引超出范围 (index < 0 || index > size()) * */ private void cheakIndexException(int index, int s){ if(index < 0 || index > this.size - s) { throw new IndexOutOfBoundsException(); } } /** * @exception NoSuchElementException - 如果此列表为空 * */ private void cheakNoSuchException(){ if(this.size == 0){ throw new NoSuchElementException(); } } /** * 迭代至index处的节点 * @param index 传入下标 * @return node 当按下标的找到的节点 * */ private Node findIndexNode(int index){ cheakIndexException(index, 1); //判断index是否越界 Node node = this.head; //判断index是否小于size的一半,如果小于就从header往后开始迭代,否则就从header往前开始迭代,提高效率 //例如有一个链表header→A→B→C→D→header if(index <= (this.size/2)) { //因为header是空的头节点,所以i要小于等于index //例如index=1, 小于size的一半2 //i=0时,node=A //i=1时,node=B,然后跳出循环 for(int i=0; i<=index; i++){ node = node.next; } }else{ //例如index=2,不小size的一半 //i=3, node等于header的前一个, node=D //i=2, node=C,然后跳出循环 for(int i=this.size - 1; i>=index; i--){ node = node.pre; } } return node; } /** * @return 此列表的元素数 * */ public int size(){ return this.size; } /** * 判断该链表中是否包含了myList链表中的所有的元素 * @param myList - 被判断的数组 * @return true - 表示包含 * @return false - 表示不包含 * */ public boolean containsAll(MyLinkedList myList){ if(myList==null){ throw new NullPointerException(); } Node otherNode = myList.head.next; while(otherNode != myList.head) { if(!this.contains(otherNode.data)) { return false; } } return true; } /** * 判断是否为空链表 * @return true - 表示为空 * @return false - 表示不为空 * */ public boolean isEmpty(){ return this.size == 0; } /** * 判断该链表中是否包含了myList链表中的所有的元素 * @param myList - 被判断的数组 * @return true - 表示删除完毕 * */ public boolean removeAll(MyLinkedList myList){ Node node = head.next; int oldSize = size; while(node != head) { Node tmp = node.next; if(myList.indexOf(node.data) != -1) { this.remove(node); } node = tmp; } return oldSize != size; } /** * 保留该链表中在与myList链表中相同的元素 * @param myList - 被判断的数组 * @return true - 表示保留完毕 * */ public boolean retainAll(MyLinkedList myList){ Node node = head.next; int oldSize = size; while(node != head) { Node tmp = node.next; if(myList.indexOf(node.data) == -1) { this.remove(node); } node = tmp; } return true; } }