此链表是以迭代的形式进行数据的输出,故继承了Iterable接口以及Iterator接口。
第一步,定义一个链表操作的标准(只实现了一些基础的功能,如数据增加、数据删除、数据量的统计以及数据清空)。
interface ILink<T> extends Iterable<T> {
void add(T data) ; // 数据增加
void remove(T data) ; // 数据删除
int size() ; // 统计数据量
void clear() ; // 数据清空
}
第二步,实现操作标准。考虑到数据增加过多时会出现StackOverFlow(栈溢出)报错,故add()方法不采用递归方式实现。
但需要注意的一点是,此自定义链表设置了最后一个节点的存储(即,Node last),若删除last节点必须要改变其引用关系,使last节点数据变为其上一个的节点。因此,我额外设置了一个preLast节点来保存last节点的上一个节点,详细代码如下:
class LinkImpl<T> implements ILink<T> {
private Node root ; // 根节点
private Node currentNode ; // 当前节点
private Node last ; // 最后一个节点
private Node preLast ; // last节点的上一个节点
private int count ; // 统计增删次数
private class Node { // 在LinkImpl实现类中定义Node节点内部类
private T data ;
private Node next ;
public Node(T data) {
this.data = data ;
}
}
@Override
public void add(T data) { // 不采用递归的形式进行数据的添加
if (data == null || "".equals(data)) {
System.err.println("所输入内容不得为空!");
}
count ++ ;
Node newNode = new Node(data) ;
if (this.root == null) {
this.root = newNode ;
} else {
this.last.next = newNode ;
/*
每次添加数据都会改变preLast节点的引用关系, 动态地设置为last节点的前一个节点
*/
this.preLast = this.last ;
}
this.last = newNode ;
}
@Override
public void remove(T data) {
if (data == null || "".equals(data)) {
System.err.println("所输入内容不得为空!");
}
count -- ;
assert data != null;
/*
若删除的是最后一个节点, 需要改变last节点的引用关系, 即last节点变为其前一个节点
*/
if (data.equals(this.last.data)) {
this.last = this.preLast ;
}
/*
若删除的是根节点
*/
if (data.equals(this.root.data)) {
this.root = this.root.next ;
/*
若删除的是其他节点
*/
} else if (this.root.next != null) {
Node temp = this.root ;
while (temp.next != null) {
// 此处使用while循环进行遍历查询要删除的数据,每次查询从根节点开始,时间复杂度为N
if (data.equals(temp.next.data)) {
temp.next = temp.next.next ;
break ;
} else {
temp = temp.next ;
}
}
}
}
@Override
public int size() {
return count ;
}
@Override
public void clear() {
this.root = null ; // 使根节点指向null即可清空整个链表的数据
}
@Override
public Iterator<T> iterator() {
this.currentNode = this.root ; // 保存当前节点,从根节点开始迭代输出
return new LinkIterator() ; // 实例化实现Iterator接口的内部类
}
private class LinkIterator implements Iterator<T> { // 定义实现Iterator接口的内部类
@Override
public boolean hasNext() {
return LinkImpl.this.currentNode != null ; // 当前节点的内容不为空时
}
@Override
public T next() {
T data = LinkImpl.this.currentNode.data ;
LinkImpl.this.currentNode = LinkImpl.this.currentNode.next ;
return data ; // 返回当前节点的内容
}
}
}
最后,进行代码测试:
删除最后一个节点:
last节点的引用关系更改成功。