算法 数据结构 双向环形链表 手撸环形链表 环形链表实现容器 环形链表添加修改删除获取大小 环形链表实现自定义容器 手撸容器 双向环形哨兵链表 数据结构(六)

  1. 环形链表:
  1. 建议先不要看我写得自己先实现下,只将Node内部类复制自己命名得容器内,

实现方法:

a. add方法(添加到头部,尾部添加,指定位置添加)

b. get方法(获取首部,获取尾部,获取指定位置)

c. remove方法(删除首部,删除尾部,删除指定位置)

d. size方法(手动维护一个size变量,实现0(1)复杂度 )

e. 迭代器(实现迭代器,能够循环遍历)

手动实现之后(每个功能只实现一种也可以),再回头参照,思考下即可!

java 复制代码
package com.nami.algorithm.study.day05;

import java.io.Serializable;
import java.util.Iterator;
import java.util.function.Consumer;

/**
 * 环形双向哨兵链表
 * 非线程安全
 * beyond u self and trust u self.
 *
 * @Author: lbc
 * @Date: 2023-09-01 9:07
 * @email: 594599620@qq.com
 * @Description: keep coding
 */
public class RingLinkedList<E> implements Serializable, Iterable<E>, Cloneable {

    /**
     * 容器已添加的元素
     */
    private int size = 1;

    /**
     * 哨兵节点
     */
    private Node sentinel = new Node(null, "-1", null);

    /**
     * 初始化哨兵
     */
    public RingLinkedList() {
        this.sentinel.prev = this.sentinel;
        this.sentinel.next = this.sentinel;
    }

    /**
     * 向链表添加数据
     *
     * @param element 添加的元素
     */
    public void addFirst(E element) {
        Node first = this.sentinel;
        Node next = first.next;
        Node node = new Node<>(first, element, next);
        first.next = node;
        next.prev = node;
        ++this.size;
    }

    /**
     * 向链表尾部添加数据
     *
     * @param element
     */
    public void addLast(E element) {
        Node last = this.sentinel.prev;
        Node node = new Node<>(last, element, sentinel);
        last.next = node;
        sentinel.prev = node;
        ++this.size;
    }
    
    /**
     * 获取容器指定位置的值
     *
     * @param index
     * @return
     */
    public E get(int index) {
        if (index > size - 1) {
            throw new IndexOutOfBoundsException("元素不存在");
        }
        Node next = sentinel.next;

        for (int i = 0; i < index; next = next.next, i++) {
        }
        if (sentinel == next) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }
        return (E) next.value;
    }

    /**
     * 获取指定位置节点node
     *
     * @param index
     * @return
     */
    private Node getNode(int index) {
        Node next = sentinel.next;

        for (int i = 0; i < index; next = next.next, i++) {
        }

        return next;
    }

    /**
     * 向元素指定节点添加值
     *
     * @param index
     * @param e
     */
    public void add(int index, E e) {
        if (index > size - 1) {
            throw new IndexOutOfBoundsException("元素不存在");
        }
        Node node = getNode(index);

        Node prev = node.prev;

        Node node1 = new Node(prev, e, node);
        node.prev = node1;
        prev.next = node1;
        ++this.size;
    }

    /**
     * 移除容器内第一个元素
     */
    public void removeFirst() {
        Node node = getNode(0);
        if (sentinel == node) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", 0));
        }
        Node prev = node.prev;
        Node next = node.next;
        prev.next = next;
        next.prev = prev;
        --this.size;
    }

    /**
     * 删除第一个元素
     */
    public void removeFirst0() {
        Node removed = this.sentinel.next;

        if (removed == this.sentinel) {
            throw new IndexOutOfBoundsException("容器内已无元素");
        }
        Node next = removed.next;

        this.sentinel.next = next;
        next.prev = this.sentinel;
    }

    /**
     * 移除容器内指定位置元素
     *
     * @param index
     */
    public void remove(int index) {
        if (index > size - 1) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }

        Node node = getNode(index);

        if (sentinel == node) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", 0));
        }

        Node prev = node.prev;

        Node next = node.next;

        prev.next = next;
        next.prev = prev;
        --this.size;
    }

    /**
     * 删除最后一个节点
     */
    public void removeLast() {
        Node prev = this.sentinel.prev;
        if (prev == this.sentinel) {
            return;
        }

        Node next = prev.next;
        Node prev0 = prev.prev;
        prev0.next = next;
        next.prev = prev0;
        --this.size;
    }

    /**
     * 获取容器大小
     *
     * @return
     */
    public int size() {
        return this.size - 1;
    }

    /**
     * 迭代器遍历
     *
     * @return
     */
    @Override
    public Iterator iterator() {
        return new NodeIterator();
    }

    /**
     * 匿名内部类
     * 内部类使用到了外部类的成员变量时,不能使用static修饰
     */
    private class NodeIterator implements Iterator {
        Node node = sentinel.next;

        @Override
        public boolean hasNext() {
            return node != sentinel;
        }

        @Override
        public Object next() {
            Object value = node.value;
            node = node.next;
            return value;
        }
    }

    /**
     * while实现
     *
     * @param consumer
     */
    public void forEach(Consumer consumer) {
        Node firstNode = this.sentinel.next;
        while (firstNode != sentinel) {
            consumer.accept(firstNode.value);
            firstNode = firstNode.next;
        }
    }

    /**
     * Node类型 节点对象
     * 二者为组合关系,所以 由外部类变为内部类,对外隐藏实现细节
     */
    private static class Node<E> {

        /**
         * 上一个节点
         */
        private Node<E> prev;

        /**
         * 值
         */
        private E value;

        /**
         * 下一个节点
         */
        private Node<E> next;


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

    }

}
相关推荐
tt5555555555558 分钟前
字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密
c++·算法·矩阵
元亓亓亓43 分钟前
LeetCode热题100--101. 对称二叉树--简单
算法·leetcode·职场和发展
躲在云朵里`1 小时前
深入理解数据结构:从数组、链表到B树家族
数据结构·b树
不会学习?1 小时前
算法03 归并分治
算法
NuyoahC2 小时前
笔试——Day43
c++·算法·笔试
2301_821919922 小时前
决策树8.19
算法·决策树·机器学习
秋难降3 小时前
别再用暴力排序了!大小顶堆让「取极值」效率飙升至 O (log n)
python·算法·排序算法
学行库小秘3 小时前
基于门控循环单元的数据回归预测 GRU
人工智能·深度学习·神经网络·算法·回归·gru
_meow_3 小时前
数学建模 15 逻辑回归与随机森林
算法·数学建模·逻辑回归
1白天的黑夜14 小时前
链表-24.两两交换链表中的结点-力扣(LeetCode)
数据结构·leetcode·链表