单向循环链表
在说单向循环链表前,我们看到这个名字,是不是已经有点想法了。毕竟我们已经学习过循环队列。
循环队列是在队列的基础上将队列头尾相连,当时我们学习的是顺序存储结构,采用的是下标循环的方法。但现在我们学习的是链式存储结构,而用链式存储结构写循环链表就很简单,只需要将尾结点存储的下一个地址改为头结点即可。
还有一个小问题,我们之前写的链表,还是基于链表实现的栈、队列,都是采用的是虚拟头结点的方法来实现的,可是我们在实现循环链表时,会发现如果有虚拟头结点,我们在遍历或者插入、删除元素时总是要考虑虚拟头结点的问题。所以今天我们就采用真实头结点来实现循环链表。
循环列表说白了就是将链表的头尾相连,如下图所示:
首先来看一下循环列表的插入动图:
上面的动图主要是插入第一个元素和头插、尾插,而一般插入和链表的一般插入是一样的
下面是循环列表的删除动图:
看完基本操作,我们再看类图:
好了,接下来,废话就不多说了,直接上代码:
package com.lfz.练习链表;
import com.lfz.练习线性表.List;
public class LoopSingle<E> implements List<E> {
private class Node {
E data;
Node next;
public Node(E data,Node next) {
this.data = data;
this.next = next;
}
}
private Node head;
private Node rear;
private int size;
public LoopSingle() {
head = new Node(null, null);
rear = head;
size = 0;
}
public Node getNode() {
return head;
}
public LoopSingle(E[] arr) {
// TODO Auto-generated method stub
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public void add(int index, E e) {
if(index<0 || index>size) {
throw new IllegalArgumentException("插入下标非法");
}
if(size==0) {
head = new Node(e, null);
rear = head;
rear.next = head;
} else if(index==0) {
Node n = new Node(e, head);
rear.next = n;
head = n;
} else if(index==size) {
Node n = new Node(e, head);
rear.next = n;
rear = n;
} else {
Node p = head;
for(int i=0;i<index-1;i++) {
p = p.next;
}
Node n = new Node(e, p.next);
p.next = n;
}
size++;
}
@Override
public void addFirst(E e) {
add(0, e);
}
@Override
public void addLast(E e) {
add(size, e);
}
@Override
public E get(int index) {
if(index<0 || index>=size) {
throw new IllegalArgumentException("查询下标非法");
}
Node p = head;
for(int i=0;i<index;i++) {
p = p.next;
}
return p.data;
}
@Override
public E getFirst() {
return get(0);
}
@Override
public E getLast() {
return get(size-1);
}
@Override
public void set(int index, E e) {
if(index<0 || index>=size) {
throw new IllegalArgumentException("修改下标非法");
}
Node p = head;
for(int i=0;i<index;i++) {
p = p.next;
}
p.data = e;
}
@Override
public boolean contains(E e) {
return find(e)!=-1;
}
@Override
public int find(E e) {
if(isEmpty()) {
return -1;
} else {
Node p = head;
for(int i=0;i<getSize();i++) {
if(p.data==e) {
return i;
}
p = p.next;
}
}
return -1;
}
@Override
public E remove(int index) {
if(index<0 || index>=size) {
throw new IllegalArgumentException("删除下标非法");
}
E e = null;
Node n;
if(size==1) {
e = head.data;
clear();
} else if(index==0) {
n = head;
e = head.data;
rear.next = head.next;
head = head.next;
n.next = null;
} else if(index==size-1) {
e = rear.data;
n = rear;
Node p = head;
while(p.next!=rear) {
p = p.next;
}
p.next = head;
rear = p;
n.next = null;
} else {
Node p = head;
for(int i=0;i<index-1;i++) {
p = p.next;
}
n = p.next;
e = p.next.data;
p.next = n.next;
n.next = null;
}
size--;
return e;
}
@Override
public E removeFirst() {
return remove(0);
}
@Override
public E removeLast() {
return remove(size-1);
}
@Override
public E removeElement(E e) {
int i = find(e);
if(i==-1) {
throw new IllegalArgumentException("删除元素不存在");
}
return remove(i);
}
@Override
public void clear() {
head = null;
rear = null;
size =0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("LoopSingle: size="+size+"\n");
if(size==0) {
sb.append("[]");
} else {
sb.append('[');
Node p = head;
while(p!=rear) {
sb.append(p.data+",");
p = p.next;
}
sb.append(rear.data+"]");
}
return sb.toString();
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj == this) {
return true;
}
if(obj instanceof LoopSingle) {
LoopSingle<E> loop = (LoopSingle<E>) obj;
if(getSize()==loop.getSize()) {
Node n = head;
Node p = loop.head;
for(int i=0;i<getSize();i++) {
if(n.data!=p.data) {
return false;
}
n = n.next;
p = p.next;
}
return true;
}
}
return false;
}
}