美文网首页
手写双向循环列表LinkedList

手写双向循环列表LinkedList

作者: 明月几何8 | 来源:发表于2019-10-27 18:51 被阅读0次
每日一新

废话不多说,直接上代码。

package cn.tedu.datastruct;

public class LinkedList<E> {

    /*
    head保存链表头节点的引用
     */
    private Node head;

    private int size;

    /**
     * Node用来描述一个节点,
     * 其中E用来存放数据,
     * prev存放前驱节点的引用,
     * next存放后继节点的引用
     */
    private class Node {
        E data;
        Node prev;
        Node next;

        public Node(E e) {
            this.data = e;
        }
    }

    /**
     * 将元素添加到链表的末尾
     *
     * @param e 待添加的元素
     * @return 添加成功返回true
     */
    public boolean add(E e) {
        if (head == null) {
            //链表为空,则当前新添加的节点为头节点
            head = new Node(e);
            head.prev = head;
            head.next = head;
            size++;
            return true;
        }
        /*
        如果链表不为空,则先找到尾节点,然后重新建立节点的引用关系
         */
        //找到尾节点
        Node last = head.prev;
        //重新建立节点的引用关系
        Node node = new Node(e);
        last.next = node;
        node.next = head;
        head.prev = node;
        node.prev = last;
        size++;
        return true;
    }

    /**
     * 在指定下标处添加新元素
     *
     * @param index    下标
     * @param element 新元素
     */
    public void add(int index, E element) {
        //判断下标的取值
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("下标越界");
        }
        //如果添加的下标等于size,即向末尾追加
        if (index == size) {
            add(element);
            return;
        }
        //得到指定下标的源节点
        Node node = getByIndex(index);
        //创建新节点
        Node newNode = new Node(element);
        //得到前一个节点
        Node prev = node.prev;
        //重新建立引用关系
        prev.next = newNode;
        newNode.next = node;
        node.prev = newNode;
        newNode.prev = prev;
        //如果添加的下标是0,则这个新节点为头结点
        if (index == 0) {
            head = newNode;
        }
        size++;
    }

    /**
     * 获得链表长度
     * @return 链表的长度
     */
    public int size() {
        return size;
    }

    /**
     * 返回指定下标的某个元素
     *
     * @param index 下标
     * @return 对应下标的某个元素
     */
    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("下标越界");
        }
        return getByIndex(index).data;
    }

    /**
     * 删除指定下标的元素
     *
     * @param index 下标
     * @return 被删除的元素
     */
    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("下标越界");
        }
        if (size == 1) {
            //只有一个节点
            E data = head.data;
            head = null;
            size--;
            return data;
        }
        //获取被删除的节点
        Node node = getByIndex(index);
        //被删除节点的前一个节点
        Node prev = node.prev;
        //被删除节点的下一个节点
        Node next = node.next;
        //重新建立引用关系
        prev.next = next;
        next.prev = prev;
        //如果删除的是第一个节点,应该让第二个节点充当头节点
        if (index == 0) {
            head = node.next;
        }
        //链表的长度减1
        size--;
        //返回被删除的元素
        return node.data;
    }

    /**
     * 返回链表中各个元素的值,如果链表为空,返回"[]",否则,各个元素值使用","分隔
     *
     * @return
     */
    @Override
    public String toString() {
        if (head == null) {
            return "[]";
        }
        Node next = head.next;
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("[" + head.data);
        /*
        开始进行遍历,直到下一个节点是头节点,则循环结束
         */
        while (next != head) {
            stringBuffer.append(", " + next.data);
            next = next.next;
        }
        stringBuffer.append("]");
        return stringBuffer.toString();
    }

    /**
     * 返回执行下标的节点
     *
     * @param index 下标
     * @return 对应下标的节点
     */
    private Node getByIndex(int index) {
        Node node = head;
        if (index <= size / 2) {
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
        } else {
            for (int i = 0; i < size - index; i++) {
                node = node.prev;
            }
        }
        return node;
    }

}

相关文章

  • 手写双向循环列表LinkedList

    废话不多说,直接上代码。

  • 搞懂Redis(二)-2:List数据结构

    List存储结构 Redis3.2前,底层是用压缩列表zipList\双向循环链表linkedList当list存...

  • LinkedList源码解析

    LinkedList简介   LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做...

  • 手写LinkedList(双向链表)

    系统jdk里的LinkedList是由一个个节点连接起来的,节点就相当于一个对象,里面有数据域和指针域,数据域是存...

  • LinkedList源码初探

    准备: LinkedList是基于链表(双向循环链表)结构的一种List,在分析LinkedList源码之前我们先...

  • LinkedList源码解析

    LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当作链表...

  • 第5章 链表

    队列 LinkedList2 use 双向链表 DoublyLinkedList2 use 循环链表 Circul...

  • List详解(ArrayList、LinkedList、Vect

    List详解 Arraylist: Object数组 LinkedList: 双向链表(JDK1.6之前为循环链表...

  • LinkedList源码解析

    先对LinkedList的特性进行一个概述:(1)LinkedList底层实现为双向循环链表。链表的特点就是插入删...

  • LinkedList源码分析

    以下内容整理自互联网,仅用于个人学习 LinkedList简介 LinkedList是基于双向循环链表实现的,除了...

网友评论

      本文标题:手写双向循环列表LinkedList

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