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

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

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

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

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

问题:头结点没有前置节点,

解决办法:为头结点造一个前置节点(不存储任何东西)--虚拟头结点

此时链表结构为:

则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判断),如下:

 1  //在链表的index(0--based)的位置添加新的元素e    (实际不常用,练习用)
 2
 3     public void add(int index, E e) {
 4         if (index < 0 || index > size) {
 5             throw new IllegalArgumentException("位置不合法");
 6         }
 7
 8         //对于头节点的特殊处理
 9         if (index == 0) {
10             addFirst(e);
11         } else {
12             Node prev = head;
13             for (int i = 0; i < index - 1; i++) {//获取到需要添加元素位置的前一个元素
14                 prev = prev.next;
15             }
16
17 //            Node node = new Node(e);
18 //            node.next = prev.next;
19 //            prev.next = node;
20
21             prev.next=new Node(e,prev.next);
22
23             size++;
24         }
25
26     }

由于现在已经统一了添加的逻辑,我们可以去掉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);
    }

改进后的完整代码为:

 1 package LinkedList;
 2
 3 public class LinkedList<E> {
 4     //将Node节点设计成私有的类中类
 5     private class Node<E> {
 6         public E e;
 7         public Node next;
 8
 9
10         //两个参数的构造函数
11
12         public Node(E e, Node next) {
13             this.e = e;
14             this.next = next;
15         }
16
17         //一个参数的构造函数
18         public Node(E e) {
19             this.e = e;
20             this.next = null;
21         }
22
23         //无参构造函数
24         public Node() {
25             this(null, null);
26         }
27
28         @Override
29         public String toString() {
30             return e.toString();
31         }
32     }
33
34     //定义头节点
35     private Node dummyHead;
36
37     //节点个数
38     private int size;
39
40
41     //无参数构造函数
42     public LinkedList() {
43         dummyHead = new Node(null, null);
44         size = 0;
45     }
46
47     //获取链表中的元素个数
48     public int getSize() {
49         return size;
50     }
51
52     //返回链表是否为空
53     public boolean isEmpty() {
54         return size == 0;
55     }
56
57     //在链表的index(0--based)的位置添加新的元素e    (实际不常用,练习用)
58
59     public void add(int index, E e) {
60         if (index < 0 || index > size) {
61             throw new IllegalArgumentException("位置不合法");
62         }
63
64         Node prev = dummyHead;//初始时prev指向dummyHead
65         for (int i = 0; i < index; i++) {//获取到需要添加元素位置的前一个元素  从dummyHead开始遍历
66             prev = prev.next;
67         }
68
69 //            Node node = new Node(e);
70 //            node.next = prev.next;
71 //            prev.next = node;
72
73         prev.next = new Node(e, prev.next);
74
75         size++;
76
77     }
78
79     //在链表头添加新的元素e
80     public void addFirst(E e) {
81         add(0, e);
82     }
83
84     //在链表末尾添加新的元素
85     public void addLast(E e) {
86         add(size, e);
87     }
88 }

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

原文地址:https://www.cnblogs.com/wfaceboss/p/10640678.html

时间: 2024-10-11 11:05:37

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

Android中Context详解 ---- 你所不知道的Context

转载至 :http://blog.csdn.net/qinjuning 前言:本文是我读<Android内核剖析>第7章 后形成的读书笔记 ,在此向欲了解Android框架的书籍推荐此书. 大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中 时刻的在与它打交道,例如:Service.BroadcastReceiver.Activity等都会利用到Context的相关方法 : 说它陌生,完全是 因为我们真正的不懂Context

Android中Context详解 ---- 你所不知道的Context (转载)

Android中Context详解 ---- 你所不知道的Context (转载) http://blog.csdn.net/qinjuning 大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中 时刻的在与它打交道,例如:Service.BroadcastReceiver.Activity等都会利用到Context的相关方法 : 说它陌生,完全是 因为我们真正的不懂Context的原理.类结构关系.一个简单的问题是,一个应用

MySQL中EXPLAIN详解

MySQL中EXPLAIN详解 explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了: 如:explain select username,first_name form hx,itlearner where a.id=b.id EXPLAIN列的解释: id:本次 select 的标识符.在查询中每个 select都有一个顺序的数值. select_type :查询类

Python中dict详解

yangyzh Python中dict详解 python3.0以上,print函数应为print(),不存在dict.iteritems()这个函数. 在python中写中文注释会报错,这时只要在头部加上# coding=gbk即可 #字典的添加.删除.修改操作dict = {"a" : "apple", "b" : "banana", "g" : "grape", "o&qu

winxp计算机管理中服务详解

winxp计算机管理中服务详解01 http://blog.sina.com.cn/s/blog_60f923b50100efy9.html http://blog.sina.com.cn/s/blog_b08c76100102vijm.html winxp计算机管理中服务详解02 http://blog.sina.com.cn/s/blog_60f923b50100efz3.html http://blog.sina.com.cn/s/blog_b08c76100102vijn.html

【转】 java中HashMap详解

原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实现类.虽然 HashMap 和 HashSet 实现的接口规范不同,但它们底层的 Hash 存储机制完全一样,甚至 HashSet 本身就采用 H

转:iOS中socket详解

一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象: 传输层.会话层.表示层和应用层则被称作主机层,是用户所面向和关心的内容. http协议   对应于应用层 tcp协议    对应于传输层 ip协议     对应于网络层 三者本质上没有可比性.  何况HTTP协议是基于TCP连接的. TCP/IP是传输层协议,主要解决数据如何在网络

Linux系统中目录详解

1.Linux文件系统的层次结构 在Linux或Unix操作系统中,所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构. 文件系统的最顶层是由根目录开始的,系统使用"/"来表示根目录.在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件.如此反复就可以构成一个庞大的文件系统. 在Linux文件系统中有两个特殊的目录,一个用户所在的工作目录,也叫当前目录,可以使用一个点"."来表示:另一个是当前目录的上一级目录,也叫父目录,可以使用两个

【转】declare-styleable的使用(自定义控件) 以及declare-styleable中format详解

原文网址:http://www.cnblogs.com/622698abc/p/3348692.html declare-styleable是给自定义控件添加自定义属性用的 1.首先,先写attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="TestAttr"> <attr name=&q