带头节点的单链表的思路及代码实现

带头,节点,单链,思路,代码,实现 · 浏览次数 : 33

小编点评

**实验结果分析** * 在添加数据节点时,我们按照4-1-2-3顺序依次加入节点。 * 这意味着当我们试图在链表中添加数据节点时,由于数据节点的顺序问题,无法按照顺序进行插入。 * 由于链表是无顺序的,我们无法通过顺序插入数据节点。 * 因此,在添加数据节点时,需要考虑如何解决顺序问题。 **解决方案** * 在添加数据节点时,我们可以尝试通过其他方式来解决顺序问题,例如: * 使用其他数据结构,例如数组,来存储数据节点。 * 将数据节点按顺序加入链表中。 * 使用排序算法来对数据节点进行排序。 **注意** * 在解决顺序问题时,需要考虑数据的顺序问题,例如:链表的顺序问题。 * 如果没有解决顺序问题的方法,可能无法在链表中添加数据节点。 * 可以通过在添加数据节点时,使用其他方式来解决顺序问题,例如:使用其他数据结构,将数据节点按顺序加入链表中,或者使用排序算法来对数据节点进行排序。

正文

带头节点的单链表的思路及代码实现(JAVA)

一、什么是的单链表

①标准定义

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) +指针(指示后继元素存储位置,元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。)

以上是标准定义不太好让人对单链表有直观的感受,下面我们通过对单链表的构成以及存储数据的方式说明,来更加深刻的理解一下什么是单链表。

②个人理解

链表存储数据的方式:

  1. 链表是以节点的方式来存储数据的

    • 那么节点又是什么呢?节点就是链表要存储的每个数据块,只不过这个数据块中不仅包含我们要存储的data,同时又多了一个next用来指向下一个数据节点所在的位置。
  2. 每个数据节点包含data域,next域:指向下一个数据节点

  3. 链表的各个节点在实际存储结构上不一定是连续的

    • 链表就是在添加数据时不去考虑数据所要添加的实际物理位置,只需要通过next域来确定数据节点的逻辑线性结构即可;
  4. 列表分带头节点的链表和不带头节点的链表,根据实际需求来确定使用哪种链表(本文以单链表进行举例说明)

    • 那么头节点的作用又是什么呢?其实头节点中有效域只有next域,用来指向链表中第一个节点所在的位置。

链表的实际结构图示:

image-20230326104918229链表的逻辑结构图示:

image-20230326105842499

二、代码实现

①定义数据节点类

// 定义数据节点类
class DataNode {

    private String data;    // data域,要存储的数据
    private DataNode next;  // next域,用于指向下一个数据节点地址

    // 数据节点构造器
    public DataNode(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "DataNode{" +
                "data='" + data + '\'' +
                '}';
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public DataNode getNext() {
        return next;
    }

    public void setNext(DataNode next) {
        this.next = next;
    }
    
}

②定义单链表类

/**
 * ClassName: SingleLinkedList
 * Package: com.zhao.test
 * Description: 定义单向链表类
 *
 * @Author XH-zhao
 * @Create 2023/3/26 11:09
 * @Version 1.0
 */
public class SingleLinkedList {

    // 先初始化一个头节点,头节点不用于存储数据,只用于指向单链表的首元素
    private DataNode head = new DataNode("");

    /**
     * 向单链表中增加数据节点
     *
     * @param dataNode 待增加的数据节点
     */
    public void addDataNode(DataNode dataNode) {

        // 由于head节点不能更改,只用于指向单链表的首元素,所以我们需要一个辅助变量接收head的引用
        DataNode temp = head;

        // 找到链表的最后,即结束
        while (temp.getNext() != null) {
            // 如果没有找到,就把下一个数据节点的引用赋值给temp,使temp指向下一个数据节点
            temp = temp.getNext();
        }

        // 将找到的最后一个一个数据节点的next域指向新加入的节点地址
        temp.setNext(dataNode);

    }

    /**
     * 显示链表的信息
     */
    public void showList() {
        // 判断链表是否为空
        if (head.getNext() == null){
            System.out.println("链表为空");
            return;
        }

        // 由于head节点不能更改,只用于指向单链表的首元素,所以我们需要一个辅助变量接收head的引用
        DataNode temp = head.getNext();

        // 遍历链表并打印链表中的数据节点
        while (temp != null) {
            System.out.println(temp);
            temp = temp.getNext();
        }

    }

}

三、实验测试单链表的代码准确性

①单链表实现以及测试的整体代码

/**
 * ClassName: SingleLinkedList
 * Package: com.zhao.test
 * Description: 定义单向链表类
 *
 * @Author XH-zhao
 * @Create 2023/3/26 11:09
 * @Version 1.0
 */
public class SingleLinkedList {

    // 先初始化一个头节点,头节点不用于存储数据,只用于指向单链表的首元素
    private DataNode head = new DataNode("");

    /**
     * 向单链表中增加数据节点
     *
     * @param dataNode 待增加的数据节点
     */
    public void addDataNode(DataNode dataNode) {

        // 由于head节点不能更改,只用于指向单链表的首元素,所以我们需要一个辅助变量接收head的引用
        DataNode temp = head;

        // 找到链表的最后,即结束
        while (temp.getNext() != null) {
            // 如果没有找到,就把下一个数据节点的引用赋值给temp,使temp指向下一个数据节点
            temp = temp.getNext();
        }

        // 将找到的最后一个一个数据节点的next域指向新加入的节点地址
        temp.setNext(dataNode);

    }

    /**
     * 显示链表的信息
     */
    public void showList() {
        // 判断链表是否为空
        if (head.getNext() == null){
            System.out.println("链表为空");
            return;
        }

        // 由于head节点不能更改,只用于指向单链表的首元素,所以我们需要一个辅助变量接收head的引用
        DataNode temp = head.getNext();

        // 遍历链表并打印链表中的数据节点
        while (temp != null) {
            System.out.println(temp);
            temp = temp.getNext();
        }

    }

}

// 定义数据节点类
class DataNode {

    private String data;    // data域,要存储的数据
    private DataNode next;  // next域,用于指向下一个数据节点地址

    // 数据节点构造器
    public DataNode(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "DataNode{" +
                "data='" + data + '\'' +
                '}';
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public DataNode getNext() {
        return next;
    }

    public void setNext(DataNode next) {
        this.next = next;
    }

}

// 单链表测试类
class SingleLinkedListTest{

    public static void main(String[] args) {

        // 创建四个数据节点
        DataNode dataNode1 = new DataNode("data1");
        DataNode dataNode2 = new DataNode("data2");
        DataNode dataNode3 = new DataNode("data3");
        DataNode dataNode4 = new DataNode("data4");

        // 创建单链表对象
        SingleLinkedList linkedList1 = new SingleLinkedList();

        // 将数据节点依次加入链表中
        linkedList1.addDataNode(dataNode1);
        linkedList1.addDataNode(dataNode2);
        linkedList1.addDataNode(dataNode3);
        linkedList1.addDataNode(dataNode4);

        // 展示链表内所有数据节点
        linkedList1.showList();
    }

}

②实验结果

DataNode{data='data1'}
DataNode{data='data2'}
DataNode{data='data3'}
DataNode{data='data4'}

进程已结束,退出代码0

从上述结果中,我们就实现了带头节点的单链表的数据存储设计。

四、实验总结

在上述的实验测试中我们已经完成了单链表存储数据的基本思想。可以让数据节点根据添加顺序依次添加到单链表当中。到这里我们仅仅实现了如何使用单链表的方式存储数据元素。那么如果我们想让数据节点在存储时,实现一些我们想要的特殊功能(例如在添加数据节点的同时,按照数据节点中的某一个属性进行排序加入),我们又该如何实现呢?

这里我们更改一下我们的测试程序,我们将数据节点以4-1-2-3顺序加入链表中,希望呈现出来还是以1-2-3-4排序好的效果。

public static void main(String[] args) {

    // 创建四个数据节点
    DataNode dataNode1 = new DataNode("data1");
    DataNode dataNode2 = new DataNode("data2");
    DataNode dataNode3 = new DataNode("data3");
    DataNode dataNode4 = new DataNode("data4");

    // 创建单链表对象
    SingleLinkedList linkedList1 = new SingleLinkedList();

    // 将数据节点以4-1-2-3顺序加入链表中
    linkedList1.addDataNode(dataNode4);
    linkedList1.addDataNode(dataNode1);
    linkedList1.addDataNode(dataNode2);
    linkedList1.addDataNode(dataNode3);

    // 展示链表内所有数据节点
    linkedList1.showList();
}
DataNode{data='data4'}
DataNode{data='data1'}
DataNode{data='data2'}
DataNode{data='data3'}

进程已结束,退出代码0

很显然,我们的代码只能按照节点加入顺序来加入节点。后续我们将在《JAVA实现节点加入到单链表时按需求排序》一文中实现上述我们想要的效果!

番外:重复增添数据节点到新链表时BUG思考

如果上述实验中我们按照如下方式去测试代码

public static void main(String[] args) {

    // 创建四个数据节点
    DataNode dataNode1 = new DataNode("data1");
    DataNode dataNode2 = new DataNode("data2");
    DataNode dataNode3 = new DataNode("data3");
    DataNode dataNode4 = new DataNode("data4");

    // 创建单链表对象
    SingleLinkedList linkedList1 = new SingleLinkedList();

    // 将数据节点依次加入链表中
    linkedList1.addDataNode(dataNode1);
    linkedList1.addDataNode(dataNode2);
    linkedList1.addDataNode(dataNode3);
    linkedList1.addDataNode(dataNode4);

    // 展示链表内所有数据节点
    linkedList1.showList();

    // 创建链表2
    SingleLinkedList linkedList2 = new SingleLinkedList();

    // 将数据节点打乱顺序加入到链表2中
    linkedList2.addDataNode(dataNode1);
    linkedList2.addDataNode(dataNode4);
    linkedList2.addDataNode(dataNode3);
    linkedList2.addDataNode(dataNode2);

    // 展示链表2内所有数据节点
    linkedList2.showList();
}

运行结果:

DataNode{data='data1'}
DataNode{data='data2'}
DataNode{data='data3'}
DataNode{data='data4'}
// 程序堵塞在这里,无法向下进行!

请思考造成上述问题的原因所在?

与带头节点的单链表的思路及代码实现相似的内容:

带头节点的单链表的思路及代码实现

带头节点的单链表的思路及代码实现(JAVA) 一、什么是的单链表 ①标准定义 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) +指针(指示后继元素存储位置,元素就是存储数据的存储单元,指针就是连接每

节点加入到单链表时按需求排序

JAVA实现节点加入到单链表时按需求排序 回顾 在上文《带头节点的单链表的思路及代码实现(JAVA)》中我们想要去实现让数据节点不考虑加入顺序实现数据节点排序效果。 那么我们要如何实现这一需求呢? 一、实现思路 ①理论思路 假设我们要根据数据节点的ID进行排序,那么我们可以通过使用待增加的节点id逐

JAVA实现单链表修改和删除数据节点

JAVA实现单链表修改和删除数据节点 一、修改单链表中的一个节点 ①实现思路 因为带头节点的链表中头节点的next域不能发生改变(始终指向单链表的头节点),否则将找不到该链表。所以我们需要先找一个辅助节点temp来进行节点代理操作。 通过遍历链表,使辅助节点temp后移,找到要修改的节点。 然后进行

.NET性能优化-是时候换个序列化协议了

计算机单机性能一直受到摩尔定律的约束,随着移动互联网的兴趣,单机性能不足的瓶颈越来越明显,制约着整个行业的发展。不过我们虽然不能无止境的纵向扩容系统,但是我们可以分布式、横向的扩容系统,这听起来非常的美好,不过也带来了今天要说明的问题,分布式的节点越多,通信产生的成本就越大。 网络传输带宽变得越来越

[转帖]单节点高并发Linux服务器影响接入能力的因素有哪些

在单台服务器承载数十万并发的情况下,影响服务器接入能力的因素已经不在是CPU、内存、带宽等表层因素,而是内核参数、设备配置、应用优化等多种细节因素。 1、最大打开文件数 Linux 中所有内容都是以文件的形式保存和管理的, 包括套接字、网络通信等资源,即一切皆文件,因此提升最大打开文件数是提高服务器

vivo版本发布平台:带宽智能调控优化实践-平台产品系列03

随着分发规模地逐步增长,各企业对CDN带宽的使用越来越多。并且,各类业务使用CDN的场景各式各样,导致带宽会不断地出现骤增骤降等问题。基于成本考虑,国内CDN厂商的计费模式主要用峰值点的带宽来计费,就算不用峰值点的带宽,也会因为峰值问题所产生的成本而抬高带宽单价。基于此,控制CDN带宽的峰谷具有重要意义,降低峰值就意味着成本节省。

Word2Vec模型总结

1.Huffman树的构造 解析:给定n个权值作为n个叶子节点,构造一棵二叉树,若它的带权路径长度达到最小,则称这样的二叉树为最优二叉树,也称Huffman树。数的带权路径长度规定为所有叶子节点的带权路径长度之和。Huffman树构造,如下所示: (1)将看成是有n颗树的森林; (2)在森林中选出两

Redis避坑指南:为什么要有分布式锁?

JUC提供的锁机制,可以保证在同一个JVM进程中同一时刻只有一个线程执行操作逻辑; 多服务多节点的情况下,就意味着有多个JVM进程,要做到这样,就需要有一个中间人; 分布式锁就是用来保证在同一时刻,仅有一个JVM进程中的一个线程在执行操作逻辑; 换句话说,JUC的锁和分布式锁都是一种保护系统资源的措施。尽可能将并发带来的不确定性转换为同步的确定性;

[转帖]小白科普丨何为树、二叉树和森林?

摘要:本文为大家带来树、二叉树和森林的表示及如何进行相互转换。 本文分享自华为云社区《树、二叉树和森林的表示及相互转换》,作者:1+1=王。 树的基本概念 树的定义:树是n(n >= 0)个节点的==有限==集。当n=0是,称为空树。 树的特点: (1)树的根没有前驱,除根外的其他节点有且仅有一个前

小白科普丨何为树、二叉树和森林?

摘要:本文为大家带来树、二叉树和森林的表示及如何进行相互转换。 本文分享自华为云社区《树、二叉树和森林的表示及相互转换》,作者:1+1=王。 树的基本概念 树的定义:树是n(n >= 0)个节点的==有限==集。当n=0是,称为空树。 树的特点: (1)树的根没有前驱,除根外的其他节点有且仅有一个前