美文网首页
循环链表

循环链表

作者: code希必地 | 来源:发表于2020-12-30 11:03 被阅读0次

1、单向循环链表

image.png

当单向循环链表只有一个元素的情况时,链表的结构如下


image.png

从单向循环链表的结构看来,只要不是在链表的头或尾进行增加和删除操作,单向循环链表的添加和删除和单向链表是相同的,需要处理的就是头尾的特殊情况。

1.1、单向循环链表的add

public void add(int index, E element) {
    checkIndexForAdd(index);
    if (index == 0) {
        if (size == 0) {
            first = new Node<>(element, null);
            first.next = first;
        } else {
            Node<E> lastNode = nodeIndex(size - 1);
            first = new Node<E>(element, first);
            lastNode.next = first;
        }
    } else {
        Node<E> preNode = nodeIndex(index - 1);
        preNode.next = new Node<>(element, preNode.next);
    }

    size++;
}

1.2、单向循环链表的remove

public E remove(int index) {
    checkIndex(index);
    Node<E> oldNode = first;
    if (index == 0) {
        if (size == 1) {
            first = null;
        } else {
            first = first.next;
            Node<E> lastNode = nodeIndex(size - 1);
            lastNode.next = first;
        }
    } else {
        Node<E> preNode = nodeIndex(index - 1);
        oldNode = preNode.next;
        preNode.next = preNode.next.next;
    }
    size--;
    return oldNode.element;
}

至此单向循环链表中接口方法已处理完毕,完整代码如下:

public class SingleCircleLinkedList<E> extends AbstractList<E> {

    private Node<E> first;

    private static class Node<E> {
        private E element;
        private Node<E> next;

        public Node(E element, Node<E> next) {
            this.element = element;
            this.next = next;
        }
    }

    @Override
    public void add(int index, E element) {
        checkIndexForAdd(index);
        if (index == 0) {
            if (size == 0) {
                first = new Node<>(element, null);
                first.next = first;
            } else {
                Node<E> lastNode = nodeIndex(size - 1);
                first = new Node<E>(element, first);
                lastNode.next = first;
            }
        } else {
            Node<E> preNode = nodeIndex(index - 1);
            preNode.next = new Node<>(element, preNode.next);
        }

        size++;
    }

    /**
     * 查找位置为index的元素
     */
    private Node<E> nodeIndex(int index) {
        checkIndex(index);
        Node<E> node = first;
        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        return node;
    }

    @Override
    public E get(int index) {
        Node<E> node = nodeIndex(index);
        return node.element;
    }

    @Override
    public E set(int index, E element) {
        Node<E> node = nodeIndex(index);
        E old = node.element;
        node.element = element;
        return old;
    }

    @Override
    public E remove(int index) {
        checkIndex(index);
        Node<E> oldNode = first;
        if (index == 0) {
            if (size == 1) {
                first = null;
            } else {
                first = first.next;
                Node<E> lastNode = nodeIndex(size - 1);
                lastNode.next = first;
            }
        } else {
            Node<E> preNode = nodeIndex(index - 1);
            oldNode = preNode.next;
            preNode.next = preNode.next.next;
        }
        size--;
        return oldNode.element;
    }

    @Override
    public int indexOf(E element) {
        if (element == null) {
            Node<E> node = first;
            for (int i = 0; i < size; i++) {
                if (node.element == null)
                    return i;
                node = node.next;
            }
        } else {
            Node<E> node = first;
            for (int i = 0; i < size; i++) {
                if (element.equals(node.element))
                    return i;
                node = node.next;
            }
        }
        return -1;
    }

    @Override
    public void clear() {
        first = null;
        size = 0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("size=" + size + " [");
        Node<E> node = first;
        for (int i = 0; i < size; i++) {
            sb.append(node.element).append("_");
            sb.append(node.next.element);
            if (i != size - 1)
                sb.append(" , ");
            node = node.next;
        }
        sb.append("]");
        return sb.toString();
    }
}

2、双向循环链表

image.png

双向循环链表只有一个节点时,链表的结构如下:


image.png

2.1、双向循环链表的add

public void add(int index, E element) {
    checkIndexForAdd(index);
    if (index == size) {
        Node<E> newNode = new Node<>(last, element, first);
        if (size == 0) {
            first = newNode;
            last = newNode;
            newNode.prev = newNode;
            newNode.next = newNode;
        } else {
            last.next = newNode;
            last = newNode;
            first.prev = last;
        }
    } else {
        Node<E> nextNode = nodeIndex(index);
        Node<E> preNode = nextNode.prev;

        Node<E> newNode = new Node<>(preNode, element, nextNode);
        preNode.next = newNode;
        nextNode.prev = newNode;

        if (index == 0) // 在向头部添加元素
            first = newNode;
    }
    size++;
}

2.2、双向循环链表的remove

public E remove(int index) {
    checkIndex(index);
    Node<E> oldNode = first;
    if (size == 1) {
        first = null;
        last = null;
    } else {
        oldNode = nodeIndex(index);
        Node<E> preNode = oldNode.prev;
        Node<E> nexNode = oldNode.next;
        preNode.next = nexNode;
        nexNode.prev = preNode;
        if (index == 0) {
            first = nexNode;
        } else if (index == size - 1) {
            last = preNode;
        }
    }
    size--;
    return oldNode.element;
}

2.3、完整代码

public class CircleLinkedList<E> extends AbstractList<E> {
    private Node<E> first;
    private Node<E> last;

    private static class Node<E> {
        private E element;
        private Node<E> next;
        private Node<E> prev;

        public Node(Node<E> prev, E element, Node<E> next) {
            this.element = element;
            this.next = next;
            this.prev = prev;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();

            sb.append(prev == null ? null : prev.element).append("_");
            sb.append(element).append("_");
            sb.append(next == null ? null : next.element);
            return sb.toString();
        }

    }

    @Override
    public void add(int index, E element) {
        checkIndexForAdd(index);
        if (index == size) {
            Node<E> newNode = new Node<>(last, element, first);
            if (size == 0) {
                first = newNode;
                last = newNode;
                newNode.prev = newNode;
                newNode.next = newNode;
            } else {
                last.next = newNode;
                last = newNode;
                first.prev = last;
            }
        } else {
            Node<E> nextNode = nodeIndex(index);
            Node<E> preNode = nextNode.prev;

            Node<E> newNode = new Node<>(preNode, element, nextNode);
            preNode.next = newNode;
            nextNode.prev = newNode;

            if (index == 0) // 在向头部添加元素
                first = newNode;
        }
        size++;
    }

    /**
     * 查找位置为index的元素
     */
    private Node<E> nodeIndex(int index) {
        checkIndex(index);
        Node<E> node = first;
        if (index <= size >> 1) {
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
        } else {
            node = last;
            for (int i = size - 1; i > index; i--) {
                node = node.prev;
            }
        }
        return node;
    }

    @Override
    public E get(int index) {
        Node<E> node = nodeIndex(index);
        return node.element;
    }

    @Override
    public E set(int index, E element) {
        Node<E> node = nodeIndex(index);
        E old = node.element;
        node.element = element;
        return old;
    }

    @Override
    public E remove(int index) {
        checkIndex(index);
        Node<E> oldNode = first;
        if (size == 1) {
            first = null;
            last = null;
        } else {
            oldNode = nodeIndex(index);
            Node<E> preNode = oldNode.prev;
            Node<E> nexNode = oldNode.next;
            preNode.next = nexNode;
            nexNode.prev = preNode;
            if (index == 0) {
                first = nexNode;
            } else if (index == size - 1) {
                last = preNode;
            }
        }
        size--;
        return oldNode.element;
    }

    @Override
    public int indexOf(E element) {
        if (element == null) {
            Node<E> node = first;
            for (int i = 0; i < size; i++) {
                if (node.element == null)
                    return i;
                node = node.next;
            }
        } else {
            Node<E> node = first;
            for (int i = 0; i < size; i++) {
                if (element.equals(node.element))
                    return i;
                node = node.next;
            }
        }
        return -1;
    }

    @Override
    public void clear() {
        first = null;
        last = null;
        size = 0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("size=" + size + " ,first=" + (first == null ? null : first.element) + " ,last="
                + (last == null ? null : last.element) + " [");
        Node<E> node = first;
        for (int i = 0; i < size; i++) {
            sb.append(node);
            if (i != size - 1)
                sb.append(" , ");
            node = node.next;
        }
        sb.append("]");
        return sb.toString();
    }
}

3、练习

3.1、解决约瑟夫问题。

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。比如N=8,M=3,则被杀的顺序如下:3->6->1->5->2->8->4->7


image.png

下面看下如何使用循环双向链表来解决约瑟夫问题,要解决这个问题,我们需要给双向循环链表增加如下几个方法:

  • 1、current用于指向某个节点
  • 2、void reset():让current指向头结点
  • 3、E next():让current向后走一步
  • 4、remove():删除current指向的节点,并让current向后移动一步
    在双向链表中加入上面接口的实现
public void reset() {
    current = first;
}

public E next() {
    if (current == null)
        return null;
    current = current.next;
    return current.element;
}

public E remove() {
    if (current == null)
        return null;
    Node<E> nexNode = current.next;
    E element = remove(current.element);
    if (size == 0)
        current = null;
    else
        current = nexNode;
    return element;
}

测试代码如下:

CircleLinkedList2<Integer> list = new CircleLinkedList2<Integer>();
for (int i = 1; i < 9; i++) {
    list.add(i);
}
list.reset();
while(!list.isEmpty()) {
    list.next();
    list.next();
    System.out.println(list.remove());
}

输出结果如下

3->6->1->5->2->8->4->7

相关文章

  • 数据结构与算法之循环链表(3.4)

    目录 单向循环链表双向循环链表约瑟夫问题如何发挥循环链表的最大威力? 一 单向循环链表 单向循环链表 - 只有一个...

  • 双向链表&双向循环链表

    链表分为:单链表、单向循环链表、双向链表、双向循环链表本节主要说明:双向链表、双向循环链表 定义结点 一、双向链表...

  • 0x05双向循环链表

    1 双向循环链表创建 2 双向循环链表插入元素 3 遍历双向循环链表 4双向循环链表删除结点

  • 10.单向循环链表SingleCycleLinkList

    目录:1.单向循环链表的定义2.单向循环链表的图解3.单向循环链表定义操作4.单向循环链表的实现 1.单向循环链表...

  • 线性表-单向循环链表

    为了方便,本文介绍的单向循环链表不包含头节点 单向循环链表内容 单向循环链表的的定义 单向循环链表的创建 单向循环...

  • 数据结构基础--单向循环链表

    单向循环链表 单向循环链表是可循环的单链表,它与单链表的区别在于单向链表的最后一个元素的指针域为空,而单向循环链表...

  • 「数据结构 三」C 语言实现循环链表

    作者原创,转载请注明出处。 个人博客:renzhe.name 本文主要讲述循环链表,双向链表。 循环链表 循环链表...

  • 2018-07-31------数据结构

    1、单链表 传送1 传送门2 2、双链表 传送门 3、循环链表 单循环链表 双向循环链表 4、静态链表 传送门 5...

  • 线性表存储结构

    数组实现 结构体实现 带头结点的单循环链表 带头结点的双循环链表 带头结点 带头结点的单循环链表和双循环链表 不管...

  • 数据结构与算法之数组与链表

    线性表包括数组,链表(单链表,双向链表,循环链表,双向循环链表,静态链表),栈(顺序栈,链式栈),队列(普通队列,...

网友评论

      本文标题:循环链表

      本文链接:https://www.haomeiwen.com/subject/lpbfoktx.html