循环单链表即将普通的单链表结成一个环,与单链表相比,循环单链表主要有以下两点差异:
1、链表初始化时需要将头指针指向自己,形成一个环。
2、遍历时不再判断下一节点不为空,而是判断下一节点不是头结点。
节点类的实现与单链表相同
//节点类
public class Node<T> {
//数据域
public T data;
//指针域
public Node<T> next;
public Node() {
}
public Node(T data) {
this.data=data;
}
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
链表实现类的初始化不一样,添加了 this.head.next = this.head; 代码串,即将头指针指向自己,形成一个环
//循环单链表
public class LinkList<T> {
// 头指针
Node<Object> head;
// 结点个数
int size;
/**
* 初始化一个空链表
*/
public LinkList() {
this.head = new Node<Object>();
this.size = 0;
this.head.next = this.head;
}
}
下面针对增删改查等基本操作进行代码实现
1、insert(Object obj) 在链表中插入元素
/**
* 在链表中插入元素
*/
public void insert(Object obj) {
// 实例化一个节点
Node<Object> node = new Node<>(obj, head);
// 第一次插入元素
if (head.next == head) {
head.next = node;
} else {
Node<Object> tmp = head;
while (tmp.next != head) {
tmp = tmp.next;
}
// 新插入的最后一个节点指向第一个节点
tmp.next = node;
}
// 每插入一个元素,节点个数+1
size++;
}
2、 traverse(String str) 对链表进行遍历,tmp.next != head即第二点差异
/**
* 遍历链表
*
*/
public void traverse(String str) {
Node<Object> tmp = head;
System.out.println(str+":");
// 从head开始遍历
while (tmp.next != head) {
System.out.print(tmp.next.data + " ");
tmp = tmp.next;
}
System.out.println();
}
3、 size()获取节点个数
/**
* 获取链表节点个数
*/
public int size() {
return this.size;
}
4、delete(int index) 删除链表中某个index节点的元素
/**
* 删除链表中某个index节点的元素
*/
public void delete(int index) {
// 范围校验
if (index > this.size-1 || index<0) {
throw new IndexOutOfBoundsException();
}
Node<Object> temp = head;
Node<Object> cur = head;
// 先让temp指针走size-index步
for (int i = size - index; i > 0; i--) {
temp = temp.next;
}
// 现在第二个指针开始走,等到第一个走完第二个指针所处的位置就是要删除的元素
while (temp.next != head) {
temp = temp.next;
cur = cur.next;
}
cur.next = cur.next.next;
size--;
}
5、deleteObj(Object obj) 删除链表中指定的元素
/**
* 删除链表中指定的元素
*/
public void deleteObj(Object obj) {
// 范围校验
if (obj == null) {
throw new IllegalArgumentException();
}
Node<Object> temp = head;
while (temp.next != head) {
if (temp.next.data.equals(obj)) {
temp.next = temp.next.next;
size--;
return;
}
temp = temp.next;
}
}
6、get(int index) 获取链表中指定节点的元素
/**
* 获取链表中指定节点的元素
*/
public Node<Object> get(int index) {
// 范围校验
if (index < 0 || index > this.size-1) {
throw new IndexOutOfBoundsException();
}
Node<Object> tmp = head;
// 从head开始遍历,直到找到链表中最后一个节点
while (index >= 0) {
tmp = tmp.next;
index--;
}
return tmp;
}
7、isEmpty() 判空
/**
* 判空
*
* @return
*/
public boolean isEmpty() {
if (size == 0) {
return true;
}
return false;
}
8、update(int index, Object obj) 修改节点元素
/**
* 修改节点元素
*/
public void update(int index, Object obj) {
// 范围校验
if (index > this.size-1 || index<0) {
throw new IndexOutOfBoundsException();
}
this.get(index).data = obj;
}
9、isExist(Object obj) 判断是否存在某元素
/**
* 判断是否存在某元素
*/
public boolean isExist(Object obj) {
// 范围校验
if (obj == null) {
throw new IllegalArgumentException();
}
Node<Object> temp = head;
while (temp.next != head) {
if (temp.next.data.equals(obj)) {
return true;
}
temp=temp.next;
}
return false;
}
以下是上面代码的测试方法
public static void main(String[] args) {
// 插入元素测试
LinkList<Object> linkList = new LinkList<>();
linkList.insert("1");
linkList.insert("3");
linkList.insert("5");
linkList.insert("7");
linkList.insert("9");
linkList.traverse("遍历");
Node<Object> node=linkList.get(3);
System.out.println("获取链表中指定节点的元素:"+node.data);
int size=linkList.size();
System.out.println("获取链表中节点个数:"+size);
boolean bol=linkList.isEmpty();
System.out.println("判空:"+bol);
linkList.update(2,"55");
linkList.traverse("修改指定下标元素");
boolean isExsit=linkList.isExist("1");
System.out.println("判断是否存在某元素:"+isExsit);
boolean isExsit2=linkList.isExist("2");
System.out.println("判断是否存在某元素:"+isExsit2);
linkList.deleteObj("55");
linkList.traverse("删除指定元素");
linkList.delete(3);
linkList.traverse("删除指定下标元素");
}
执行结果如下:
遍历:
1 3 5 7 9
获取链表中指定节点的元素:7
获取链表中节点个数:5
判空:false
修改指定下标元素:
1 3 55 7 9
判断是否存在某元素:true
判断是否存在某元素:false
删除指定元素:
1 3 7 9
删除指定下标元素:
1 3 7
以上所有代码均可直接运行,源码地址:https://download.csdn.net/download/xuewenyong/11110545