单向循环链表:
什么是单向循环链表?
如果把单链表的最后一个节点的指针指向链表头部,而不是指向NULL,那么就构成了一个单向循环链表,通俗讲就是把尾节点的下一跳指向头结点。
为什么要使用单向循环链表?
在单向链表中,头指针是相当重要的,因为单向链表的操作都需要头指针,所以如果头指针丢失或者破坏,那么整个链表都会遗失,并且浪费链表内存空间,因此我们引入了单向循环链表这种数据结构。
如下图所示:
单向循环链表我们需要注意一个问题:
在链表中我们使用的是虚拟头结点,但是在循环链表中我们在遍历的时候就会遇到麻烦,因此在单向循环链表中我们使用的是真实头结点。
具体的实现示意图如下图所示:
单向循环链表的插入:
单向循环链表的插入与单向链表有所不同,因为单向循环链表首尾相连,所以没有从尾部插入的问题。
(1)从链表头部插入
将新插入的节点变为链表头部,next指向原来的第一个节点,在遍历整个链表找到链表末尾(即它的next指向的是head的那个节点),将这个节点的next指向新插入的节点,最后再将链表头指针指向新节点。
(2)从链表中间插入
此时插入的过程和单向链表的一样,找到要插入位置前驱节点,将前驱节点的next指向新节点的next,再将前驱节点的next指向新插入的节点。
单向循环链表的类图如下图所示:
具体代码实现如下图所示:
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;
}