单向链表的Java实现
首先在了解单向链表之前,简单说一下普通数组存在的致命缺陷,即普通数组一旦定义,那么它的长度便不可更改,而链表可以解决这样的缺陷,比如在超市购物时,买了一瓶饮料,两瓶洗衣液,突然我看见货架的另外一边还有另外一种品牌的洗衣液,此刻若是想要换掉一瓶洗衣液,那么我需要从之前已经挑好的两瓶中放回货架,类似于数组的删除操作,显然在已知想要买多少东西的时候是可以使用简单数组的,可要是临时有需要加一点呢?此时就轮到了链表(动态数组)。
部分实现代码:
package stu.java.lch;
//1、数据增加 2、获取数据个数 3、空集合判断
//4、返回链表数据 5、获取指定索引数据
//6、修改指定索引的数据 7、判断指定数据是否存在
//8、数据删除 9、清空集合(链表)
interface ILink<E> { //设置泛型,链表的标准
public void add(E e) ; //1、数据增加
public int size() ; //2、获取数据个数
public boolean isEmpty() ; //3、判断是否为空
public Object [] toArray() ;//4、将链表(集合)元素以数组的形式返回
public E get(int index) ; //5、根据索引获取数据
public void set(int index, E data) ; //6、修改索引数据
public boolean contains(E data) ; //7、判断指定数据是否存在
public void remove(E e) ; //8、数据删除
public void clean() ; //9、清空集合(链表)
}
class LinkImpl<E> implements ILink<E> {
private class Node { //保存节点的数据关系
private E data ; //保存的数据
private Node next ; //保存下一个引用
public Node(E data) { //有数据的情况下才有意义
this.data = data ;
}
public void addNode(Node newNode) { //保存新的Node数据
if (this.next == null) { //当前节点的下一个节点为null
this.next = newNode ; //保存当前节点
} else {
this.next.addNode(newNode);
}
}
public void toArrayNode() {
//4、将当前节点的数据取出保存到returnData数组中,同时进行索引自增
LinkImpl.this.returnData [LinkImpl.this.foot ++ ] = this.data ;
if (this.next != null) { //4、还有下一个数据
this.next.toArrayNode();
}
}
//5、
public E getNode(int index) {
if (LinkImpl.this.foot ++ == index) { //索引相同
return this.data ; //返回当前数据
} else {
return this.next.getNode(index) ;
}
}
//6、
public void setNode(int index, E data) {
if (LinkImpl.this.foot ++ == index) { //索引相同
this.data = data ; //6、修改数据
} else {
this.next.setNode(index,data) ;
}
}
//7、
public boolean containsNode(E data) {
if (data.equals(this.data)) { //7、对象比较
return true ;
} else {
if (this.next == null) { //7、没有后续节点了
return false ; //找不到
} else {
return this.next.containsNode(data) ; //向后继续判断
}
}
}
//8、
public void removeNode(Node previous,E data) {
if (this.data.equals(data)) {
previous.next = this.next ; //空出当前节点
} else {
if (this.next != null) { //有后续节点
this.next.removeNode(this, data); //向后继续删除
}
}
}
}
//-----------------以下为Link类中定义的成员--------------------
private Node root ; //保存根元素
private int count ; //2、保存数据的个数
private int foot ; //4、描述的是操作数组的脚标
private Object [] returnData ;//4、返回的数据保存
//-----------------以下为Link类中定义的方法--------------------
public void add(E e) {
if (e == null) { //保存的数据为空
return ;
}
//数据本身是不具有关联特性的,只有Node类有,要想实现关联关系必须将数据包装在Node类中
Node newNode = new Node(e) ; //创建一个新的节点
if (this.root == null) {
this.root = newNode ;//第一个节点作为根节点
} else {
this.root.addNode(newNode) ; //将新节点保存在合适的位置
}
this.count ++ ; //2、保存元素个数自增
}
public int size() {
return this.count ; //2、返回元素个数
}
public boolean isEmpty() {
return this.count == 0 ;
}
//4、
public Object[] toArray() {
if (this.isEmpty()) {
return null ;
//throw new NullPointerException("集合内容为空") ;
}
this.foot = 0 ; //4、脚标清零
this.returnData = new Object [this.count] ; //4、根据已有的长度开辟数组
this.root.toArrayNode(); //4、利用Node类进行递归数据获取
return this.returnData ; //4、返回全部元素
}
//5、
public E get(int index) {
if (index >= this.count) { //5、索引应该在指定范围之内
return null ;
} //索引数据的获取应该由Node类完成
this.foot = 0 ; //重置索引的下标
return this.root.getNode(index) ;
}
//6、
public void set(int index,E data) {
if (index >= this.count) { //6、索引应该在指定范围之内
return ; //方法结束
} //索引数据的获取应该由Node类完成
this.foot = 0 ; //重置索引的下标
this.root.setNode(index,data) ; //修改数据
}
//7、
public boolean contains(E data) {
if (data == null) {
return false ; //没有数据
}
return this.root.containsNode(data) ; //交给Node类判断
}
//8、
public void remove(E data) {
if (this.contains(data)) { //判断数据是否存在
if (this.root.data.equals(data)) { //根节点为要删除节点
this.root = this.root.next ; //根的下一个节点
} else { //交给Node类进行删除
this.root.next.removeNode(this.root, data);
}
this.count -- ;
}
}
//9、
public void clean() {
this.root = null ; //后续所有节点都没了
this.count = 0 ; //个数清零
}
}
若有不当之处,请各位大佬给予指正。
注:若有侵权,请联系作者删除,谢谢!