恋上数据结构与算法:双向循环链表(八)

文章目录

(一)双向循环链表:简介
(二)双向循环链表:add
(三)双向循环链表:remove
(四)增强型双向循环链表
(五)练习:约瑟夫问题(Josephus Problem)
(六)静态链表
(七)作业题
(八)进一步优化ArrayList

(一)双向循环链表:简介

双向链表的基础上,第一个节点的prev指向最后一个节点,最后一个节点的next指向第一个节点,就是双向循环链表
恋上数据结构与算法:双向循环链表(八)_第1张图片
同样的,我们只需要关注add()方法和remove()方法

(二)双向循环链表:add

恋上数据结构与算法:双向循环链表(八)_第2张图片
首先考虑只有1个节点(add后)的情况,代码如下:
恋上数据结构与算法:双向循环链表(八)_第3张图片
然后考虑往尾节点的位置添加节点,代码如下:
恋上数据结构与算法:双向循环链表(八)_第4张图片
整体代码如下:

    @Override
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        if (index == size) {//往最后面添加元素
            Node<E> oldLast = last;
            last = new Node<E>(element, oldLast, first);//新的last节点的next是first
            if (oldLast == null) {//这是链表添加的第一个元素
                first = last;
                first.next = first;
                first.prev = first;
            } else {
                oldLast.next = last;//只需要再接last前一个结点的next就可以了
                first.prev = last;
            }
        } else {//往前面添加元素
            Node<E> next = node(index);//如果要往2的位置添加,那2就是新元素的next
            Node<E> prev = next.prev;//新节点的上一个元素就是2的上一个(就是1)
            Node<E> node = new Node<>(element, prev, next);//已经接好两根线了(新节点的prev和next)
            next.prev = node;
            prev.next = node;
            if (index == 0) {
                first = node;
            }
        }
        size++;
    }

(三)双向循环链表:remove

恋上数据结构与算法:双向循环链表(八)_第5张图片
最后考虑只有1个节点的情况后,整体代码如下:

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

测试结果如下:
恋上数据结构与算法:双向循环链表(八)_第6张图片

(四)增强型双向循环链表

恋上数据结构与算法:双向循环链表(八)_第7张图片
代码如下:

    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> next = current.next;
        E element = remove(current);
        if (size == 0) {
            current = null;
        } else {
            current = next;
        }

        return element;
    }

    private E remove(Node<E> node) {
        if (size == 1) {
            first = null;
            last = null;
        } else {
            Node<E> prev = node.prev;
            Node<E> next = node.next;
            prev.next = next;
            next.prev = prev;

            if (node == first) { // index == 0
                first = next;
            }

            if (node == last) { // index == size - 1
                last = prev;
            }
        }

        size--;
        return node.element;
    }

之前的remove(int index)方法也可以被优化,如下:

    @Override
    public E remove(int index) {
        rangeCheck(index);
        return remove(node(index));
    }

(五)练习:约瑟夫问题(Josephus Problem)

恋上数据结构与算法:双向循环链表(八)_第8张图片

    static void josephus() {
        CircleLinkedList<Integer> list = new CircleLinkedList<>();
        for (int i = 1; i <= 8; i++) {
            list.add(i);
        }

        // 指向头结点(指向1)
        list.reset();

        while (!list.isEmpty()) {
            list.next();
            list.next();
            System.out.println(list.remove());
        }
    }

    public static void main(String[] args) {
        josephus();
    }

效果如下:
恋上数据结构与算法:双向循环链表(八)_第9张图片

(六)静态链表

恋上数据结构与算法:双向循环链表(八)_第10张图片
注意:把这个-1改成0,就变成循环链表
恋上数据结构与算法:双向循环链表(八)_第11张图片

(七)作业题

203. 移除链表元素:https://leetcode-cn.com/problems/remove-linked-list-elements/
83. 删除排序链表中的重复元素:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
876. 链表的中间结点:https://leetcode-cn.com/problems/middle-of-the-linked-list/

(八)进一步优化ArrayList

之前的ArrayList对0号节点进行增删操作都是很慢的,我们可以用一个first变量去优化,如下:
恋上数据结构与算法:双向循环链表(八)_第12张图片
此时删除0号节点,并且更新first的值
恋上数据结构与算法:双向循环链表(八)_第13张图片
再删除一个
恋上数据结构与算法:双向循环链表(八)_第14张图片
此时再往0号节点的位置添加节点
恋上数据结构与算法:双向循环链表(八)_第15张图片
再增加一个
恋上数据结构与算法:双向循环链表(八)_第16张图片
如果此时还要再增加一次,情况如下:
恋上数据结构与算法:双向循环链表(八)_第17张图片
此时可以通过取模运算来获取真实的位置
如:

  • 下一个元素的位置 :(8+1)%9=0,真实位置是0
  • 再下一个元素的位置:(8+1+1)%9=1,真实位置是1

如果要往红色框框的位置增加节点,之前的做法是挪动后面的节点
恋上数据结构与算法:双向循环链表(八)_第18张图片
现在我们可以挪动比较少的节点的一边(左边的两个),然后更新first
恋上数据结构与算法:双向循环链表(八)_第19张图片
删除节点也类似,这里不再演示

你可能感兴趣的:(恋上数据结构与算法:第一季)