单向循环链表实现
1.1 基本介绍
循环链表,顾名思义,链表整体要形成一个圆环状。在单向链表中,最后一个节点的指针为null
,不指向任何结点,因为没有下一个元素了。要实现循环链表,只需要让单向链表的最后一个节点的指针指向头结点即可。
1.2 添加操作
1、思路分析
链表为空的时候
让head
和tail
同时指向这个结点,让尾结点的下一跳指向头结点。
头部添加
先让要添加的元素指向head
,然后再将head
指针指向新结点。
最后让tail
指针下一跳重新指向头结点
尾部添加
直接让新结点的下一跳指向头结点
当前尾节点指向新节点
最后tail
指针移动到新节点
2、代码示例
接口类:List
package cn.linkedlist.demo02;
/***
* List接口
* @param <E>
*/
public interface List<E> extends Iterable<E>{
void add(E element);
void add(int index, E element) ;
void remove(E element);
E remove(int index);
E get(int index);
E set(int index, E element) ;
int size();
int indexOf(E element) ;
boolean contains(E element);
boolean isEmpty();
void clear();
}
链表类:LinkedSinglyCircularList
package cn.linkedlist.demo02;
import java.util.Iterator;
// 单向循环链表
public class LinkedSinglyCircularList<E> implements List<E>{
// 创建Node节点
private class Node{
//数据域 用来存储数据的
public E data;
//指针域 用来存储下一个结点对象的地址
public Node next;
// 构造方法
public Node() {
this(null, null);
}
public Node(E data) {
this(data, null);
}
public Node(E data, Node next) {
this.data = data;
this.next = next;
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append(data).append("->").append(next.data);
return sb.toString();
}
}
// 链表元素的数量
private int size;
//链表当中的头指针指向第一个结点对象
private Node head;
//链表当中的头指针指向最后一个结点对象
private Node tail;
// 初始化链表
public LinkedSinglyCircularList(){
head = null;
tail = null;
size = 0;
}
public LinkedSinglyCircularList(E[] arr){
for (E e : arr){
add(e);
}
}
/***
* 在链表末尾添加新的元素e
* @param element
*/
@Override
public void add(E element) {
add(size, element);
}
/***
* 根据链表的index位置添加新的元素e
* @param index
* @param element
*/
@Override
public void add(int index, E element) {
if (index < 0|| index > size) {
throw new ArrayIndexOutOfBoundsException("add index out of bounds");
}
// 创建新的结点对象
Node node = new Node(element);
if(isEmpty()){
// 链表为空
head = node;
tail = node;
tail.next = head;
}else if(index == 0){
// 在链表头部添加元素
node.next = head;
head = node;
tail.next = head;
}else if(index == size){
node.next = tail.next;
// 在链表尾部添加元素
tail.next = node;
tail = node;
}else{
// 在链表中添加元素
Node prev = head;
for(int i=0; i < index -1; i++){
prev = prev.next;
}
node.next = prev.next;
prev.next = node;
}
size++;
}
/***
* 得链表的第index个位置的元素
* @param index
* @return
*/
@Override
public E get(int index) {
if (index < 0|| index > size) {
throw new ArrayIndexOutOfBoundsException("get index out of bounds");
}
// 获取头部
if(index == 0){
return head.data;
}else if(index == size -1){
// 获取尾部
return tail.data;
}else{
// 获取中间
Node prev = head;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
return prev.data;
}
}
/***
* 修改链表中指定index的元素为element
* @param index
* @param element
* @return
*/
@Override
public E set(int index, E element) {
if (index < 0|| index > size) {
throw new ArrayIndexOutOfBoundsException("update index out of bounds");
}
// 定义返回值
E result = null;
if(index == 0){
// 修改头部
result= head.data;
head.data = element;
}else if(index == size -1){
// 修改尾部
result = tail.data;
tail.data = element;
}else{
// 修改中间的元素
Node prev = head;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
result = prev.data;
prev.data = element;
}
return result;
}
@Override
public int size() {
return size;
}
/***
* 查找元素在链表中第一次出现的索引
* @param element
* @return
*/
@Override
public int indexOf(E element) {
// 判断链表是否为空
if(isEmpty()){
return -1;
}
// 定义prev指针
Node prev = head;
// 定义索引值
int index = 0;
while (!prev.data.equals(element)){
prev = prev.next;
index++;
// 如果没有找到,则返回-1
if(prev == null){
return -1;
}
}
return index;
}
/***
* 查找链表中是否有元素element
* @param element
* @return
*/
@Override
public boolean contains(E element) {
return indexOf(element)!= -1;
}
/***
* 判断链表是否为空
* @return
*/
@Override
public boolean isEmpty() {
return size == 0 && head == null && tail == null;
}
@Override
public void clear() {
head = null;
tail = null;
size = 0;
}
/***
* 迭代器实现
* @return
*/
@Override
public Iterator<E> iterator() {
return new LinkedSinglyCircularListIterator();
}
class LinkedSinglyCircularListIterator implements Iterator<E>{
// 定义游标
private Node cur = head;
// 创建flag,表示还可以继续循环
private boolean flag = true;
@Override
public boolean hasNext() {
if(isEmpty()){
return false;
}
return flag;
}
@Override
public E next() {
E ret = cur.data;
cur = cur.next;
// 再次判断,是否已经循环完一圈
if(cur == head){
flag = false;
}
return ret;
}
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("size=").append(size).append(", [");
Node node = head;
for (int i = 0; i < size; i++) {
if (i != 0) {
res.append(", ");
}
res.append(node);
node = node.next;
}
res.append("]");
return res.toString();
}
}
测试类:LinkedSinglyCircularListDemo
package cn.linkedlist.demo02;
public class LinkedSinglyCircularListDemo {
public static void main(String[] args) {
LinkedSinglyCircularList<Integer> list1 = new LinkedSinglyCircularList<>();
System.out.println("===链表头部插入===");
list1.add(0,1);
list1.add(0,3);
list1.add(0,5);
list1.add(0,8);
System.out.println(list1);
System.out.println("==链表尾部插入==");
list1.add(12);
System.out.println(list1);
System.out.println("===链表中间插入===");
list1.add(2, 23);
System.out.println(list1);
}
}
2、执行结果
1.3 删除操作
1、思路分析
删除头结点
head
指向下一个结点
原头结点的下一跳置空,让尾指针的下一跳重新指向头结点。
删除成功!!!
删除尾节点
定义一个指针prev
,找到删除尾部节点的前驱。
让prev.next
直接指向头结点
最后让tail
指向新节点
删除成功!!!
2、代码示例
链表类:LinkedSinglyCircularList
/***
* 删除链表中指定的元素element
* @param element
*/
@Override
public void remove(E element) {
int index = indexOf(element);
if(index != -1){
remove(index);
}
}
/***
* 删除链表中指定索引处index的元素
* @param index
* @return
*/
@Override
public E remove(int index){
if (index < 0|| index > size) {
throw new ArrayIndexOutOfBoundsException("remove index out of bounds");
}
// 定义返回值
E result = null;
// 当链表只剩下一个元素
if(size == 1){
result = head.data;
head = null;
tail = null;
}else if(index == 0){
// 删除链表头部
Node prev = head;
result = prev.data;
head = prev.next;
// 置空操作
prev.next = null;
tail.next = head;
}else if(index == size -1){
// 删除链表尾部
Node prev = head;
while (prev.next != tail){
prev = prev.next;
}
result = tail.data;
// 修改操作
prev.next = tail.next;
tail = prev;
}else{
// 删除中间的某个元素
Node prev = head;
for (int i = 0; i < index -1; i++) {
prev = prev.next;
}
Node deleteNode = prev.next;
result = deleteNode.data;
prev.next = deleteNode.next;
// 置空
deleteNode.next = null;
}
size --;
return result;
}
测试类:LinkedSinglyCircularListDemo
package cn.linkedlist.demo06;
public class SingleCircleLinkedListDemo {
public static void main(String[] args) {
SingleCircleLinkedList<Integer> singleLinkedList = new SingleCircleLinkedList<>();
singleLinkedList.add(0,1);
singleLinkedList.add(0,3);
singleLinkedList.add(0,5);
singleLinkedList.add(0,8);
singleLinkedList.add(12);
singleLinkedList.add(2, 23);
System.out.println("===删除链表节点前====");
System.out.println(singleLinkedList);
System.out.println("===删除链表节点后====");
// 根据链表index位置的元素, 返回删除的元素
singleLinkedList.remove(2);
System.out.println(singleLinkedList);
// 删除链表中的元素
singleLinkedList.removeElement(12);
System.out.println(singleLinkedList);
}
}
2、执行结果