美文网首页数据结构和算法分析数据结构
链表----在链表中添加元素详解--使用链表的虚拟头结点

链表----在链表中添加元素详解--使用链表的虚拟头结点

作者: wfaceboss | 来源:发表于2019-04-02 10:45 被阅读0次

在上一小节中关于在链表中头部添加元素与在其他位置添加元素在逻辑上有所差别,这是由于我们在给链表添加元素时需要找到待添加元素位置的前一个元素所在的位置,但对于链表头来说,没有前置节点,因此在逻辑上就特殊一些,操作方式也就有所差别,需单独处理。为了针对头结点的操作方式与其他方式一致:接下来我们就一步一步引入今天的主题--使用虚拟头结点。

首先来看看之前的节点结构--第一个是头结点


image.png

相应的逻辑代码,感兴趣的可以看看我上一篇相关介绍,点击传送地址

为了能把关于头结点的操作与其他操作统一起来,我们来分析一下情况:

问题:头结点没有前置节点,
解决办法:为头结点造一个前置节点(不存储任何东西)--虚拟头结点
此时链表结构为:

image.png
dummyHead节点变为了0这个节点(头结点)的前置节点,则现在所有节点都有了前置节点,在逻辑可以使用统一的操作方式。下面对代码进行改写:
(1)将之前对头结点的定义改为对虚拟头结点的定义
将原来定义的头结点代码
private Node head;

改为

private Node dummyHead;

(2)链表构造函数初始化时对虚拟节点进行初始化
将原来对头结点的初始化

//无参数构造函数
    public LinkedList() {
        head =null;
        size = 0;
    }

改为对虚拟节点的初始化,虚拟头节点为初始化为空节点。(空链表时存在一个唯一的虚拟头结点)

//无参数构造函数
    public LinkedList() {
        dummyHead = new Node(null, null);
        size = 0;
    }

(3)改进之前的add(int index,E e)方法,之前对在头结点添加元素单独做了处理(if-else判断),如下:

//在链表的index(0--based)的位置添加新的元素e    (实际不常用,练习用)

    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("位置不合法");
        }

        //对于头节点的特殊处理
        if (index == 0) {
            addFirst(e);
        } else {
            Node prev = head;
            for (int i = 0; i < index - 1; i++) {//获取到需要添加元素位置的前一个元素
                prev = prev.next;
            }

//            Node node = new Node(e);
//            node.next = prev.next;
//            prev.next = node;

            prev.next=new Node(e,prev.next);

            size++;
        }

    }

由于现在已经统一了添加的逻辑,我们可以去掉if-else判断,prev初始时指向虚拟头结点(dummyHead),由于增加了一个虚拟头结点(dummyHead)且是从该节点开始计算,此时我们为了找到index前面一个节点,只需遍历index次。

//在链表的index(0--based)的位置添加新的元素e    (实际不常用,练习用)
    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("位置不合法");
        }

        Node prev = dummyHead;//初始时prev指向dummyHead
        for (int i = 0; i < index; i++) {//获取到需要添加元素位置的前一个元素  从dummyHead开始遍历
            prev = prev.next;
        }

//            Node node = new Node(e);
//            node.next = prev.next;
//            prev.next = node;

        prev.next = new Node(e, prev.next);

        size++;

    }

(4)改进addFirst()方法,该方法依托于add(int index,E e)方法

   //在链表头添加新的元素e
    public void addFirst(E e) {
        add(0, e);
    }

改进后的完整代码为:

package LinkedList;

public class LinkedList<E> {
    //将Node节点设计成私有的类中类
    private class Node<E> {
        public E e;
        public Node next;


        //两个参数的构造函数

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

        //一个参数的构造函数
        public Node(E e) {
            this.e = e;
            this.next = null;
        }

        //无参构造函数
        public Node() {
            this(null, null);
        }

        @Override
        public String toString() {
            return e.toString();
        }
    }

    //定义头节点
    private Node dummyHead;

    //节点个数
    private int size;


    //无参数构造函数
    public LinkedList() {
        dummyHead = new Node(null, null);
        size = 0;
    }

    //获取链表中的元素个数
    public int getSize() {
        return size;
    }

    //返回链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //在链表的index(0--based)的位置添加新的元素e    (实际不常用,练习用)

    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("位置不合法");
        }

        Node prev = dummyHead;//初始时prev指向dummyHead
        for (int i = 0; i < index; i++) {//获取到需要添加元素位置的前一个元素  从dummyHead开始遍历
            prev = prev.next;
        }

//            Node node = new Node(e);
//            node.next = prev.next;
//            prev.next = node;

        prev.next = new Node(e, prev.next);

        size++;

    }

    //在链表头添加新的元素e
    public void addFirst(E e) {
        add(0, e);
    }

    //在链表末尾添加新的元素
    public void addLast(E e) {
        add(size, e);
    }
}

本小节着重介绍了虚拟头节点的使用,若您觉得本文还行、还过得去,麻烦给个喜欢吧,谢谢!!

相关文章

  • LRU 缓存

    采用哈希表+双向链表的数据结构,双向链表创建虚拟头结点、虚拟尾结点,用来查询最近最少使用的元素,刚刚使用或添加的元...

  • 链表----在链表中添加元素详解--使用链表的虚拟头结点

    在上一小节中关于在链表中头部添加元素与在其他位置添加元素在逻辑上有所差别,这是由于我们在给链表添加元素时需要找到待...

  • c语言链表操作

    链表的创建 链表原地翻转 链表结点删除 头插法添加结点 修改链表某个结点的值 相当于查找元素,修改其关联元素的值 ...

  • 线性表元素插入和删除

    单链表(链式存储结构)插入 单链表(链式存储结构)删除 有头结点的单链表在开始结点前插入元素等同在头结点后插入元素...

  • 链表头结点存在的意义

    转载:单链表为什么要设置头结点 问题:在单链表中使用“头结点”,这个哑结点始终是链表的第一个元素,这个技巧的利与弊...

  • 双链表

    双链表 整体结构 初始化 添加元素 添加为头结点 图示: 添加为尾结点 数组元素添加进入链表 1 添加到尾部的形式...

  • 单链表头节点的作用

    转载:小星雪单链表为什么要设置头结点 问题:在单链表中使用“头结点”,这个哑结点始终是链表的第一个元素,这个技巧的...

  • 数据结构-链表和递归

    使用链表解决问题 leetcode 203号问题 给定的节点 不使用虚拟头结点 如果链表头部是需要删除的元素, 直...

  • 链表

    内容 链表数据结构 向链表添加元素 从链表移除元素 使用 LinkedList 表 双向链表 循环链表 链表数据结...

  • 链表

    头指针与头结点的异同 头指针为链表的必要元素,指向第一个结点(若有头结点则指向头结点) 头结点为链表的非必要元素(...

网友评论

    本文标题:链表----在链表中添加元素详解--使用链表的虚拟头结点

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