手写双向循环列表LinkedList

2019-10-27  本文已影响0人  明月几何8
每日一新

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

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

}
上一篇 下一篇

猜你喜欢

热点阅读