单链表的实现还是很基础的,首先写个节点类:
public class Node<T> {
public T data;
public Node<T> next;
public Node(T data,Node<T> next){
this.data=data;
this.next=next;
}
public Node(){
this(null,null);
}
public String toString(){
return this.data.toString();
}
}
然后就是单链表的各种操作了,插入删除重置遍历等,因为JAVA虚拟机可以自动回收没用的空间,所以不必手动删除。单链表的实现还是很简单,很基础的。需要注意的是链表删除某一个节点,只需要把上一个节点对应的下节点变成这个节点的下一个节点就行了;插入某点是也是通过节点操作:
public class SinglyList<T> {
public Node <T> head; //为了方便,单链表要有头结点,即使表为空里面也有元素。
public SinglyList() {
this.head=new Node<T>();
}
public SinglyList(T[] values){ //把数组转化成链表
this();
Node<T> rear=this.head;
for(int i=0;i<values.length;i++){
rear.next=new Node<T>(values[i],null);
rear=rear.next;
}
}
public boolean isEmpty(){ //判断是否为空,只需要判断头结点是否具有下一个节点即可。
return this.head.next==null;
}
public T get(int i){ //获取链表的第i个元素,如果i不在范围内,则返回null
Node<T> p=this.head.next;
for(int j=0;p!=null&&j<i;j++)
p=p.next;
return (i>=0&&p!=null)?p.data:null;
}
public void set(int i,T x){ //将链表的第i个元素设置为x
Node<T> p=this.head;
int j;
for(j=0;p!=null&&j<i;j++){ //先遍历数组,如果在范围内,就直接设置,如果在最后一个,在开辟一个空间,否则抛出异常
p=p.next;
}
if(j!=i){throw new IndexOutOfBoundsException("设置超出范围");}
p=new Node <T>(x,p.next);
}
public int size(){ //遍历链表求其长度
int count=0;
Node<T> p=this.head;
while(p.next!=null){
p=p.next;
count++;
}
return count;
}
public String toString() { //返回类名
String str=this.getClass().getName()+"(";
for(Node<T> p=this.head.next;p!=null;p=p.next){
str+=p.data.toString();
if(p.next!=null)str+=",";
}
return str+")";
}
public Node<T> insert(int i,T x){ // 第i位插入,如果不够i位则插入最后一位
if(x==null)
throw new NullPointerException("x==null");
Node<T> p=this.head;
for(int j=0;p.next!=null&&j<i;j++)p=p.next;
p.next=new Node<T>(x,p.next);
return p.next;
}
public Node<T> insert(T x){
return insert(Integer.MAX_VALUE,x); //直接在一个很大的位置插入,等同于插入最后一位
}
public T remove(int i){ //删除第i个节点,返回删除内容
Node<T> p=this.head;
for(int j=0;p.next!=null&&j<i;j++)p=p.next; //循环同查询一样,循环后p.next为查找内容
if(i>=0&&p.next!=null){ //如果要删除这一位不是null,并且在范围内就删除
T old=p.next.data;
p.next=p.next.next; //因为JAVA虚拟机自动删除用不到的东西,所以无需写析构函数
return old;
}
return null;
}
public void clear(){this.head.next=null;} //清楚函数很简单,直接删除,垃圾由JAVA虚拟机回收
public Node<T> search(T key){ //查找首个和key相等的节点,找不到返回null;
if(key==null) new NullPointerException("key==null"); //如果查找值为null,抛出异常
Node<T> p=this.head.next; //以第一个点为起点,依次往下查找
while(p!=null&&!key.equals(p.data)){
p=p.next;
}
return p;
}
public boolean contains(T key){ //查询是否包含key
return search(key)!=null;
}
public Node<T> insertDiffent(T x){ //插入不相同元素,如果不存在就插入
if(x==null) new NullPointerException("x==null");
Node<T> p=this.head;
while(p.next!=null&&!x.equals(p.next.data)){
p=p.next;
}
if(p.next==null){p.next=new Node<T>(x,null);}
return p.next;
}
public T remove(T key){ //移除首次出现的key
if(key==null) new NullPointerException("x==null");
Node<T> p=this.head;
while(p.next!=null&&!key.equals(p.next.data)){
p=p.next;
}
T old=p.next.data;
if(p!=null)p.next=p.next.next;
return old;
}
}
最后我写了个简单测试各个函数的测试类,没有发现什么BUG,如果大佬们发现了可以指点一下(●ˇ∀ˇ●)
public class Main {
public static void main(String[] args) {
Integer arr[]={1,2,3,4,5};
SinglyList<Integer> list=new SinglyList<Integer>(arr);
System.out.println(list.toString());
list.remove(2);
System.out.println(list.toString());
list.remove(new Integer(2));
System.out.println(list.toString());
System.out.println("现在链表中有"+list.size()+"个元素");
list.insert(2,2);
System.out.println(list.toString());
for(int i=10;i<15;i++)list.insert(i);
System.out.println(list.toString());
list.insertDiffent(10);
System.out.println(list.toString());
list.insertDiffent(3);
System.out.println(list.toString());
System.out.println("11的下一个节点是"+list.search(11).next);
System.out.println("链表的第3个节点是:"+list.get(2));
}
}
测试结果:
链表.SinglyList(1,2,3,4,5)
链表.SinglyList(1,2,4,5)
链表.SinglyList(1,4,5)
现在链表中有3个元素
链表.SinglyList(1,4,2,5)
链表.SinglyList(1,4,2,5,10,11,12,13,14)
链表.SinglyList(1,4,2,5,10,11,12,13,14)
链表.SinglyList(1,4,2,5,10,11,12,13,14,3)
11的下一个节点是12
链表的第3个节点是:2
参考书籍《数据结构(JAVA)》第四版。