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;
}
}