数据结构 之 双链表

双链表

双链表在单链表的基础上进行扩展,一个节点中包含三部分:数据、前一个节点的指针、后一个节点的指针。双链表可以提高单链表的综合性能。在一个双链表中要维护着 first 指针和 last 指针 以及 链表的大小。

节点设计

    private static class Node<E> {
        E element;
        Node next;
        Node prev;

        public Node(E elements, Node prev, Node next) {
            this.element = elements;
            this.next = next;
            this.prev = prev;
        }

        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            if (prev != null) {
                builder.append(prev.element);
            } else {
                builder.append("null");
            }
            builder.append("_").append(element).append("_");
            if (next != null) {
                builder.append(next.element);
            } else {
                builder.append("null");
            }
            return builder.toString();
        }
    }

添加节点

在双向链表中添加元素的关键步骤就是连接两条线:前一个节点的next 、后一个节点的prev,有了这两个线就可以把两个节点连接到一起。默认是在尾部添加新节点。由于双向链表维护了尾部节点,所以在添加元素的时候就可以直接使用尾部节点,而不用向单链表一样每次都要查找出来尾部节点。

指定位置添加新节点

添加到首部位置

public void add(int index, E element) {
    
    rangeCheckOfAdd(index);
    // 顺序添加元素,直接在尾部进行添加
    if (index == size) {    
        Node<E> oldLast = last;
        // 维护最新的尾部节点
        last = new Node<>(element, oldLast, null);
        /**
         * 如果是第一次 添加元素
         * 头节点和尾节点都指向这个元素
         */
        if (oldLast == null) {
            first = last;
        } else {
            // 不是第一次添加
            oldLast.next = last;
        }
        //  载指定的位置添加元素
    } else {
        //  找这个位置的节点
        Node<E> next = node(index);
        // 得到前一个节点
        Node prev = next.prev;
        // 新建节点,并且连接节点的前驱、后继节点
        Node<E> node = new Node<>(element, prev, next);
        // 为后继节点连接其前驱节点 
        next.prev = node;
        /**
         * 此时向第一个位置加入, 更新 first 指针
         */
        if (prev == null) {
            first = node;
        } else {
            // 连接前驱节点的后继节点
            prev.next = node;
        }
    }
    size++;
}

删除节点

对于链表来说,添加、删除操作简而言之就是对指针的改变 。得到要删除节点的前驱和后继节点,然后改变前驱节点的next指向、后继节点的prev指向即可。

普通删除

删除首部

删除尾部

public E remove(int index) {
    rangeCheck(index);
    //  得到这个节点
    Node<E> node = node(index);
    // 后继
    Node next = node.next;
    // 前驱
    Node prev = node.prev;
    /**
     * 对删除首部、尾部元素做出特殊处理
     */
    if (prev == null) {
        // 删除首部元素
        first = next;
    } else {
        prev.next = next;
    }

    if (next == null) {
        // 删除尾部元素
        last = prev;
    } else {
        next.prev = prev;
    }
    size--;
    return node.element;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值