当你让单链表的尾指针指向头结点时,一个单向循环链表就诞生了!
循环链表:
当然,单向循环没这么简单。
首先,若你之前知道的单链表是有虚拟头结点的,那么在单向循环链表中,虚拟头结点是多余的,
其次,由于末尾结点指针域是不再指向null的,在操作时,是要考虑到的,
由于这两个问题,单向循环链表的重点就在于增加结点和删除结点的部分。
所以这次我们着重于增加和删除两个方法,整体LoopSingle的实现放在文章末尾
add(int index,E e):
第0步:
判断插入下标是否合法,同时新建结点,给数据域赋值
if (index < 0 || index > size) {
throw new IllegalArgumentException("插入位置不合法");
}
Node node = new Node();
node.data = e;
增加时,我们有四种情况:
1.第一个结点还未创建,这时head,rear指针都应该指向null。添加结点后,头尾指针都指向新加结点,同时末尾结点的next指向头结点即它自己的next域指向了它自己
if (size == 0) { //当结点元素个数为0,则链表无元素
head = node; //使头指针指向新建结点
rear = node; //使尾指针指向新建结点
node.next = node; //使尾结点的next域指向头结点
}
2.在0下标处添加结点,即头插。这时我们先要将新建结点next域指向头结点,之后让尾结点的next域指向新建结点,最后让头指针指向新建结点
else if (index == 0) { // 头插
node.next = head; // 新建结点的next域指向头结点
rear.next = node; //尾结点的next域指向新建结点
head = node; //将新建结点设置为头结点
}
3.在末尾添加结点,即尾插。这时我们先要将新建结点next域指向头结点,然后将尾结点的next域指向新建结点,最后将rear指针指向新建结点。
else if (index == size) { // 尾插
node.next = head; //新建结点的next域指向头结点
rear.next = node; //尾结点的next域指向新建结点
rear = node; //将新建结点设置为尾结点
}
4.指定下标插入元素。这时的操作与单链表的随机插入操作一致,就是for循环找到插入位置前一个结点,然后让新建结点next域指向它的next域,最后让它的next域指向新建结点。
else { //一般情况下的操作
Node temp = head; //建立临时结点
for (int i = 0; i < index - 1; i++) { //找到插入位置前一个结点
temp = temp.next;
}
node.next = temp.next;
temp.next = node;
}
size++; //最后别忘了给size加一
最后别忘了给size加一!!!最后别忘了给size加一!!!最后别忘了给size加一!!!
remove(int index)
依然时第0步:判断删除下标是否合法
if (index < 0 || index > size - 1) {
throw new IllegalArgumentException("要删除的下标不合法");
}
E e = null; //存放将要删除的元素
删除时任由四种情况:
1.删除时只剩一个元素。这时执行删除操作后,我们要让头尾指针指向null
if (size == 1) { //此时链表只有一个元素
e = head.data; //获取将要删除元素
head.next = null; //清空next域
rear.next = null;
head = null; //将head置空
rear = null; //将rear置空
}
2.删除头结点。将尾结点的next域指向头结点的next域,头结点next域置空,head指向rear的next域结点
else if (index == 0) { // 头删
e = head.data; //获取删除元素
rear.next = head.next; //尾结点的next域指向头结点的next域
head.next = null; //头结点的next域置空
head = rear.next; //重新设置头结点
}
3.删除尾结点。遍历链表找到尾结点的前序结点,将前序结点的next域指向头结点,将尾结点的next域置空,使rear指针指向前序结点
else if (index == size - 1) { // 尾删
Node temp = head; //临时结点
for(int i=0;i<size-2;i++){ //注意!!!想找到尾结点之前的结点,要循环size-2次
temp = temp.next;
}
e = rear.data; //获取删除数据
temp.next = head; //前序指向头结点
rear.next = null; //尾指针next域置空
rear = temp; //更新尾指针
}
4.删除任意中间元素。找到删除结点前序结点,将前序结点next指向删除结点next域,将删除结点next域置空
else { //一般情况
Node temp = head; //临时结点
for (int i = 0; i < index - 1; i++) { //遍历找到删除结点前序结点
temp = temp.next;
}
e = temp.next.data; //获取删除结点数据
Node n = temp.next; //新建临时结点指向删除结点
temp.next = temp.next.next; //将前序结点的next域指向删除结点的next域
n.next = null; //将删除结点的next域置空
n = null; //将临时结点置空
}
size--; //依然不要忘了size--
return e; //返回删除元素
其他部分比较简单,这里就不细讲了,直接上代码。
public class LoopSingle<E> implements List<E> { //实现List接口(自定义,感兴趣可翻看之前文章)
/**
* 结点定义
*/
private class Node {
private E data;
private Node next;
public Node() {
this(null, null);
}
public Node(E data, Node node) {
this.data = data;
this.next = node;
}
@Override
public String toString() {
return data.toString();
}
}
private Node head; //头指针
private Node rear; //尾指针
private int size; //当前链表元素个数
public LoopSingle() {
head = null;
rear = null;
size = 0;
}
@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("下标越界");
}
Node node = new Node();
node.data = e;
if (size == 0) { // 链表为空的情况处理
head = node;
rear = node;
node.next = node;
} else if (index == 0) { // 头插
node.next = head;
rear.next = node;
head = node;
} else if (index == size) { // 尾插
node.next = rear.next;
rear.next = node;
rear = node;
} else {
Node temp = head;
for (int i = 0; i < index - 1; i++) {
temp = temp.next;
}
node.next = temp.next;
temp.next = node;
}
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 - 1) {
throw new IllegalArgumentException("下标越界");
}
Node node = head;
if (index == 0) {
// 什么也不做
} else if (index == size - 1) {
node = rear;
} else {
for (int i = 0; i < index; i++) {
node = node.next;
}
}
return node.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 - 1) {
throw new IllegalArgumentException("下标越界");
}
Node node = head;
if (index == 0) {
// 什么也不做
} else if (index == size - 1) {
node = rear;
} else {
for (int i = 0; i < index; i++) {
node = node.next;
}
}
node.data = e;
}
@Override
public boolean contains(E e) { //判断指定元素是否存在与链表中
if (isEmpty()) {
return false;
}
Node node = head;
for (int i = 0; i < size; i++) {
if (node.data == e) {
return true;
}
node = node.next;
}
return false;
}
@Override
public int find(E e) { //查找指定元素在链表中的下标
if (!contains(e)) {
return -1;
}
Node node = head;
for (int i = 0; i < size; i++) {
if (node.data == e) {
return i;
}
node = node.next;
}
return -1;
}
@Override
public E remove(int index) { //删除指定下标元素
if (index < 0 || index > size - 1) {
throw new IllegalArgumentException("下标越界");
}
E e = null;
if (size == 1) {
e = head.data;
head.next = null;
head = null;
rear = null;
} else if (index == 0) { // 头删
e = head.data;
rear.next = head.next;
head.next = null;
head = rear.next;
} else if (index == size - 1) { // 尾删
Node temp = head;
for(int i=0;i<size-2;i++){ //注意!!!想找到尾结点之前的结点,要循环size-2次
temp = temp.next;
}
e = rear.data;
temp.next = head;
rear.next = null;
rear = temp;
} else {
Node temp = head;
for (int i = 0; i < index - 1; i++) {
temp = temp.next;
}
e = temp.next.data;
Node n = temp.next;
temp.next = temp.next.next;
n.next = null;
}
size--;
return e;
}
@Override
public E removeFirst() { //删除表头元素
return remove(0);
}
@Override
public E removeLast() { //删除表尾元素
return remove(size - 1);
}
@Override
public void removeElement(E e) { //删除指定元素
int index = find(e);
if (index != -1) {
remove(index);
} else {
System.out.println("删除元素不存在");
}
}
@Override
public void clear() { //清空循环链表
head = null;
rear = null;
size = 0;
}
@Override
public boolean equals(Object obj) { //重写的比较方法
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof LoopSingle) {
LoopSingle ls = (LoopSingle) obj;
if (ls.size == getSize()) {
Node node = head;
Node n = ls.head;
for (int i = 0; i < size; i++) {
if (node.data != n.data) {
return false;
}
node = node.next;
n = n.next;
}
return true;
}
}
return false;
}
@Override
public String toString() { //重写的toString方法
StringBuilder sb = new StringBuilder();
sb.append("LoopSingle " + "size:" + size + "\n");
if (isEmpty()) {
sb.append("[]");
} else {
Node node = head;
sb.append("[");
while (node != rear) {
sb.append(node.data + ",");
node = node.next;
}
sb.append(node.data + "]");
}
return sb.toString();
}
}