关于linkedList的一些理解,欢迎各位大佬指错
import util.Iterable;
import util.Iterator;
import util.List;
import java.util.NoSuchElementException;
public class LinkedList<T> implements List<T> {
@Override
public Iterable<T> iterator() {
return null;
}
/**
* 定义了内部类,用来表示链表中节点的是四种情况
*
* @param <t>
*/
private class Node<t> {
//链表单个节点的三个属性
Node<T> prve; //节点的头(头指针)
T t; //节点的值
Node<T> next; //节点的尾(尾指针)
/**
* 全参构造,同时也代表了了中间节点
* 特点是:头指针指向不为空,有值(可以为null),尾指针指向不为空
*
* @param prve //中间节点的头
* @param t //中间节点的值
* @param next //中间节点的尾
*/
public Node(Node<T> prve, T t, Node<T> next) {
this.prve = prve;
this.t = t;
this.next = next;
}
/**
* 代表尾节点
* 特点是:头指针指向不为空,有值(可以为null),尾指针指向为空
*
* @param prve //尾节点的头
* @param t //尾节点的值
*/
public Node(Node<T> prve, T t) {
this(prve, t, null);
}
/**
* 代表了这个链表只有一个节点
* 特点是:头指针指向为空,有值(可以为null),尾指针指向为空
*
* @param t //节点的值
*/
public Node(T t) {
this.t = t;
}
/**
* 代表头节点
* 特点是:头指针指向为空,有值(可以为null),尾指针指向不为空
*
* @param t //头节点的值
* @param next 头节点的尾
*/
public Node(T t, Node<T> next) {
this(null, t, next);
}
}
private int size; //表示链表中节点(元素)的个数
private Node<T> root; //表示链表的头节点
private Node<T> curr; //表示链表的尾节点
/**
* 定义了一个方法,这个方法是用来寻找对应下标在链表中对应的值
*
* @param index //所需要的下标
* @return //返回值为 这个下标对应的值
*/
Node<T> node(int index) {
/**
* 将链表一分为二,当index的值小于链表数量的一半时执行 if
* 大于链表数量的一半时执行else
*/
if (index < (size >> 1)) {
Node<T> x = root; //声明一个链表节点x,并将x的赋值为root
//循环遍历,直到遍历到下标为index-1
for (int i = 0; i < index; i++) {
x = x.next;//每次循环将x的值变为当前节点next(尾指针)所指向的值(就是下一个节点的值)
}
return x;//返回index下标对应的值
} else {
Node<T> x = curr;//声明一个链表节点x,并将x的赋值为curr
//循环遍历,直到遍历到下标为index+1
for (int i = size - 1; i > index; i--) {
x = x.prve;//每次循环将x的值变为当前节点prve(头指针)所指向的值(就是上一个节点的值)
}
return x;//返回index下标对应的值
}
}
@Override
public boolean add(T t) {
/**
* 当size的值为0时执行 if
* 部位0时执行else
*/
if (size == 0) {
/**
* 当为0时,代表链表里一个元素都没有
* 所以头元素就等于这个新增的元素
* 尾元素也等于这个新增的元素
* 同时这个节点的头指针和尾指针也没有需要指向的内容
*/
root = new Node<>(t);
curr = root;
} else {
/**
* 不为0时,我们需要把这个节点加到末尾
* 调用尾节点方法,声明一个节点temp
* 同时这个尾节点的头指针指向的是原来链表的尾节点
* 所以,头指针的值是curr,这个节点的值是t
*/
Node<T> temp = new Node<>(curr, t);
curr.next = temp;//原来链表的尾节点的尾指针应当指向新增的节点,所以将temp赋给curr.next
curr = temp; //执行完上面的操作之后,现在链表的尾节点应当变成新增的节点。所以把curr的值变为temp
}
size++;//每执行一次增加操作,size++
return true;
}
@Override
public void add(int index, T t) {//在指定下标添加元素
/**
* 先判定下标是狗越界,越界就抛异常
*/
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("index out of bounds:" + index);
}
//第一中情况,指定下标是0
if (index == 0) {
addFirst(t);//直接调用在头部增加函数的方法
} else if (index == size-1) {//第二中情况,指定下标是尾
add(t);//直接调用上面的方法(上面方法就是在末尾添加元素)
} else {//第三种情况,在中间添加元素
//声明一个节点x,并调用node方法,将x的附值为需要下标在原链表对应的值
Node<T> x = node(index);
/**
* 声明一个节点temp,并赋值为需要添加的元素
* 同时头指针对应的值为x的头指针所指向的节点(元素)(原链表对应下标的前一个节点)
* 值为t
* 尾指针指向的值为x
*/
Node<T> temp = new Node<>(x.prve, t, x);
x.prve.next = temp;//在插入之后,原链表对应下标的前一个节点的尾指针应当指向新增的节点
x.prve = temp;//在插入之后,原链表对应下标的头指针应当指向新增的节点
}
size++;//每执行一次增加操作,size++
}
@Override
public boolean addAll(T[] arr) {
if (null == arr) {//先判定所加集合 是否为空。为空加了没变化
System.out.println("所加集合为空");
return false;
}
//直接用循环(或者迭代器)依次重复add方法加节点的过程,直到所有元素都被加到末尾
for (T t : arr) {
add(t);
size++;//每执行一次增加操作,size++
}
return true;
}
@Override
public boolean addAll(int index, T[] arr) {
/**
* 先判定下标是狗越界,越界就抛异常
*/
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("index out of bounds:" + index);
}
if (null == arr) {//先判定所加集合 是否为空。
add(index, (T) arr);//为null也可以加,所以调用一次在指定位置加的方法
}
//直接用循环(或者迭代器)依次重复add(在指定位置加)方法加节点的过程,直到所有元素都被加到末尾
for (T t : arr) {
add(index, t);
size++;//每执行一次增加操作,size++
}
return true;
}
@Override
public void addFirst(T t) {//在头部增加
if (size == 0) {
/**
* 当为0时,代表链表里一个元素都没有
* 所以头元素就等于这个新增的元素
* 尾元素也等于这个新增的元素
* 同时这个节点的头指针和尾指针也没有需要指向的内容
*/
root = new Node<>(t);
curr = root;
} else {
/**
* 不为0时,我们需要把这个节点加到头部
* 调用头节点方法,声明一个节点temp
* 同时这个头节点的头指针指向的是原来链表的头节点
* 所以,这个节点尾指针的值是root,这个节点的值是t
*/
Node<T> temp = new Node<>(t, root);
root.prve = temp;//原来链表的头节点的头指针应当指向新增的节点,所以将temp赋给root.prve
root = temp;//执行完上面的操作之后,现在链表的头节点应当变成新增的节点。所以把root的值变为temp
}
size++;//每执行一次增加操作,size++
}
@Override
public void addLast(T t) {//在末尾加一个节点,直接调用add方法,一样
add(t);
}
@Override
public void clear() {//清除链表中所有元素
/**
* 直接用循环将每个节点都变为空
* 先声明一个节点x。将头节点的值赋给x
* 循环的条件值节点x不存在,所以会一直循环
*/
for (Node<T> x = root; x != null; ) {
Node<T> next = x.next;//将(x.next就是)下一个节点的值给新声明的节点next
x.t = null;//将x的值置空
x.next = null;//将x的头指针的引用置空
x.prve = null;//将x的尾指针置空
x = next;//将节点x赋值为next(下一个节点)
}
root = curr = null;//循环结束之后,再将头和尾置空
size = 0;//循环结束之后,将size置0
}
@Override
public Object clone() {//就是浅拷贝一份链表
Node<T> clone;//声明一个新链表clone
/**
* 直接用循环
* 将头节点的值赋给clone
* 循环的条件值clone这个节点不存在,所以会一直循环
* 每循环一次clone的值变为原节点的下一个
*/
for (clone = root; clone != null; clone = clone.next) {
add(clone.t);//每次循环其实都是调用add方法,就是一个一个节点往clone上面加
}
return clone;//返回clone
}
@Override
public int indexOf(Object o) {//寻找指定元素的下标(从左往右第一次出现)
int index = 0;//声明下标,并先假定为0;
/**
* 如果需要寻找的元素为null则执行if
* 如果需要寻找的元素不是null则执行else
*/
if (o == null) {
/**
* 直接用循环
* 先声明一个节点x。将头节点的值赋给x
* 循环的条件值x这个节点不存在
* 每循环一次的值变为原节点的下一个
*/
for (Node<T> x = root; x != null; x = x.next) {
if (x.t == null) {//如果x对应的值t为null执行{ }里的内容
return index;//能执行这行代码就表示找到了,返回这个下标
}
index++;//每循环一次index++
}
} else {
/**
* 直接用循环
* 先声明一个节点x。将头节点的值赋给x
* 循环的条件值x这个节点不存在
* 每循环一次的值变为原节点的下一个
*/
for (Node<T> x = root; x != null; x = x.next) {
if (o.equals(x.t))//如果x对应的值t和所需要寻找的值相等执行{ }中的内容
return index;//能执行这行代码就表示找到了,返回这个下标
index++;//每循环一次index++
}
}
return -1;//上面的结果都不成立,就是没找到。返回-1
}
@Override
public int LastIndexOf(Object o) {//寻找指定元素的下标(从右往左第一次出现,也就是从左往右最后一次出现)
int index = size-1;//声明下标,并先假定为size;
/**
* 如果需要寻找的元素为null则执行if
* 如果需要寻找的元素不是null则执行else
*/
if (o == null) {
/**
* 直接用循环
* 先声明一个节点x。将尾节点的值赋给x
* 循环的条件值x这个节点不存在
* 每循环一次的值变为原节点的上一个
*/
for (Node<T> x = curr; x != null; x = x.prve) {
if (x.t == null) {//如果x对应的值t为null执行{ }里的内容
return index;//能执行这行代码就表示找到了,返回这个下标
}
index--;//每循环一次index++
}
} else {
/**
* 直接用循环
* 先声明一个节点x。将尾节点的值赋给x
* 循环的条件值x这个节点不存在
* 每循环一次的值变为原节点的上一个
*/
for (Node<T> x = curr; x != null; x = x.prve) {
if (o.equals(x.t)) {//如果x对应的值t和所需要寻找的值相等执行{ }中的内容
return index;//能执行这行代码就表示找到了,返回这个下标
}
index--;//每循环一次index++
}
}
return -1;//上面的结果都不成立,就是没找到。返回-1
}
@Override
public boolean contains(Object t) {//判断所要寻找的元素在链表中是否存在
/**
* 直接调用indexOf方法
* 因为如果存在,调用indexOf方法之后会返回一个下标。
* 这个下标肯定不为-1.所以不等于-1.返回值为true
* 如果不存在indexOf返回值为-1,-1 != -1 为false
*/
return -1 != indexOf(t);
}
@Override
public int size() {//记录链表中元素的个数
return size;//返回个数
}
后面还有一半,关于迭代器的方法没具体些,因为自己掌握的还不是很好。