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

  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;
        }

    }

}
相关推荐
算法歌者14 分钟前
[算法]入门1.矩阵转置
算法
林开落L29 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色30 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
tyler_download32 分钟前
手撸 chatgpt 大模型:简述 LLM 的架构,算法和训练流程
算法·chatgpt
SoraLuna1 小时前
「Mac玩转仓颉内测版7」入门篇7 - Cangjie控制结构(下)
算法·macos·动态规划·cangjie
我狠狠地刷刷刷刷刷1 小时前
中文分词模拟器
开发语言·python·算法
鸽鸽程序猿1 小时前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
九圣残炎1 小时前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode
YSRM1 小时前
Experimental Analysis of Dedicated GPU in Virtual Framework using vGPU 论文分析
算法·gpu算力·vgpu·pci直通
韭菜盖饭2 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode