链表结构的基本概念和操作

数据结构之——链表 链表的介绍,单链表和双向链表的接口实现。 阅读详情

链表结构

什么是链表结构

在这里插入图片描述

如图所示,链表中的每个阶段都应包括如下部分:

  • 数据部分:保存的是该结点的实际数据
  • 地址部分:保存的是下一个结点的地址
    由于采用了引用来指示下一个数据的地址,因此在链表结构中。逻辑上相邻的节点在内存中并不一定相邻,逻辑相邻关系通过地址部分的引用变量来实现

使用链表的优缺点

优点:

  • 结点之间不要求连续存放,因此在保存大量数据时,不需要分配一块连续的存储空间。用户可以用new函数动态分配结点的存储空间,当删除某个结点时,给该节点赋值null,释放其占用的内存空间。

缺点:

  • 那就是浪费存储空间。因此,对于每个节点数据,都要额外保存一个引用变量。但是,在某些场合,链表结构所带来的好处还是大于其缺点的。

  • 对于链表的访问只能从表头逐个查找,即通过head头引用找到第一个结点, 再从第一个结点找到第二个节点……这样逐个比较一直到找到需要的结点为止,而不能像顺序表那样进行随机访问。

    链式存储是最常用的存储方式之一 ,它不仅可用来表示线性表,而且可用来表示各种非线性数据结构。

链表结构还可以细分为如下几类:

  • 单链表:同上面的链式结构-一样,每个结点中只包含一个引用。

  • 双向链表:若每个结点包含两个引用,一个指向下一个结点, 另一个指向上一个结点,说是双向链表。

  • 单循环链表:在单链表中,将终端节点的引用域null改为指向表头节点或开始节点即可构成单循环链表

  • 多重链的循环链表:如果将表中结点链在多个环上,将构成多重链的循环链表。

1.准备数据

有了前面的理论知识后,开始链表结构的程序设计。准备链表操作中需要用到的变量及类等。示例代码如下:

class DATA2 {
    //节点的关键字
    String key;
    String name;
    int age;
}

/**
 * 定义链表结构
 */

class CLType {
    DATA2 nodeData = new DATA2();
    CLType nextNode;
}

上述代码定义了链表数据元素的类DATA2及链表的类CLType.结点的具体数据保存在一个类DATA2中,而引用nextNode用来指向下一个结点。
其实,可以认为该链表是一个班级学生的记录,其中, key为学号,name 为学生的名称,age 为年龄。和顺序表所完成的工作类似。

2.追加结点

追加结点即在链表末尾增加一个结点。表尾结点的地址部分原来保存的是空地址null, 此时需将其设置为新增结点的地址(即原表尾结点指向新增结点),然后将新增结点的地址部分设置为空地址null,即新增结点成为表尾。
由于般情况下,链表只有个头引用head,要在末尾添加结点就需要从头引用head开始逐个检查,直到找到最后一个结点(即表尾)。
典型的追加结点的过程如图2-4所示。追加结点的操作步骤如下:

在这里插入图片描述

(1)首先分配内存空间,保存新增的结点。
(2)从头引用head开始逐个检查,直到找到最后一个结点(即表尾)。
(3)将表尾结点的地址部分设置为新增结点的地址。
(4)将新增结点的地址部分设置为空地址null,即新增结点成为表尾。

实例代码如下:

CLType CLAddEnd(CLType head, DATA2 nodeData) {
    CLType node, htemp;
    node = new CLType();
    if (node == null) {
        System.out.println("申请内存失败!");
        return null;
    } else {
        node.nodeData = nodeData;
        node.nextNode = null;
        if (head == null) {
            head = node;
            return head;
        }
        htemp = head;
        //查找表的末尾
        while (htemp.nextNode != null) {
            htemp = htemp.nextNode;
        }
        htemp.nextNode = node;
        return head;
    }
3.插入头节点

在这里插入图片描述

(1)首先分配内存空间,保存新增的结点。
(2)使新增节点指向头引用head所指向的节点
(3)使用头引用head指向新增节点

代码实例如下:

CLType CLAddFirst(CLType head, DATA2 nodeData) {
    CLType node;
    node = new CLType();
    if (node == null) {
        System.out.println("申请内存失败!");
        return null;
    } else {
        node.nodeData = nodeData;
        node.nextNode = null;
        head = node;
        return head;
    }
}
4.查找节点
CLType CLFindNode(CLType head, String key) {
    CLType htemp;
    htemp = head;
    while (htemp != null) {
        if (htemp.nodeData.key.compareTo(key) == 0) {
            return htemp;
        }
        htemp = htemp.nextNode;
    }
    return null;
}
5.插入节点

插入节点就是在链表中间部分的指定位置增加入结点。插入节点的操作步骤如下:
(1)分配内存空间,保存新增的结点。
(2)找到要插入的逻辑位置,也就是位于哪两个结点之间。
(3)修改插入位置结点的引用,使其指向新增结点,而使新增节点指向原插入位置所指向的节点。

在这里插入图片描述

CLType CLInsertNode(CLType head, String findkey, DATA2 nodeData) {
    CLType node, nodetemp;
    node = new CLType();
    if (node == null) {
        System.out.println("申请内存失败!");
        return null;
    }
    node.nodeData = nodeData;
    nodetemp = CLFindNode(head, findkey);
    if (nodetemp != null) {
        node.nextNode = nodetemp.nextNode;
        nodetemp.nextNode = node;
    } else {
        System.out.println("未找到正确的位置!");
    }
    return head;
}
6/删除节点

删除节点的操作步骤如下:
(1)查找需要删除的节点。
(2)使前一节点指向当前节点的下一节点
(3)删除节点

在这里插入图片描述

int CLDeleteNode(CLType head, String key) {
    //node保存删除节点的前一节点
    CLType node, htemp;
    htemp = head;
    node = head;
    while (htemp != null) {
        if (head.nodeData.key.compareTo(key) == 0) {
            node.nextNode = htemp.nextNode;
            //释放内存
            htemp = null;
            return 1;
        } else {
            node = htemp;
            htemp = htemp.nextNode;
        }
    }
    return 0;

}
7.计算链表长度
int CLLength(CLType head) {
    CLType htemp;
    int Len = 0;
    htemp = head;
    while (htemp != null) {
        Len++;
        htemp = htemp.nextNode;
    }
    return Len;
}
8.显示所有节点
void CLAllNode(CLType head) {
    CLType htemp;
    DATA2 nodeData;
    htemp = head;
    System.out.println("当前链表共有" + CLLength(head) + "个节点。链表所有的数据如下:");
    while (htemp != null) {
        nodeData = htemp.nodeData;
        System.out.println("节点:" + nodeData.key + " " + nodeData.name + " " + nodeData.age);
        htemp = htemp.nextNode;
    }
}

链表操作实例

import java.util.Scanner;

class DATA2 {
    //节点的关键字
    String key;
    String name;
    int age;
}

/**
 * 定义链表结构
 */

class CLType {
    DATA2 nodeData = new DATA2();
    CLType nextNode;


    CLType CLAddEnd(CLType head, DATA2 nodeData) {
        CLType node, htemp;
        node = new CLType();
        if (node == null) {
            System.out.println("申请内存失败!");
            return null;
        } else {
            node.nodeData = nodeData;
            node.nextNode = null;
            if (head == null) {
                head = node;
                return head;
            }
            htemp = head;
            //查找表的末尾
            while (htemp.nextNode != null) {
                htemp = htemp.nextNode;
            }
            htemp.nextNode = node;
            return head;
        }

    }

    CLType CLAddFirst(CLType head, DATA2 nodeData) {
        CLType node;
        node = new CLType();
        if (node == null) {
            System.out.println("申请内存失败!");
            return null;
        } else {
            node.nodeData = nodeData;
            node.nextNode = null;
            head = node;
            return head;
        }
    }

    CLType CLFindNode(CLType head, String key) {
        CLType htemp;
        htemp = head;
        while (htemp != null) {
            if (htemp.nodeData.key.compareTo(key) == 0) {
                return htemp;
            }
            htemp = htemp.nextNode;
        }
        return null;
    }

    CLType CLInsertNode(CLType head, String findkey, DATA2 nodeData) {
        CLType node, nodetemp;
        node = new CLType();
        if (node == null) {
            System.out.println("申请内存失败!");
            return null;
        }
        node.nodeData = nodeData;
        nodetemp = CLFindNode(head, findkey);
        if (nodetemp != null) {
            node.nextNode = nodetemp.nextNode;
            nodetemp.nextNode = node;
        } else {
            System.out.println("未找到正确的位置!");
        }
        return head;
    }

    int CLDeleteNode(CLType head, String key) {
        //node保存删除节点的前一节点
        CLType node, htemp;
        htemp = head;
        node = head;
        while (htemp != null) {
            if (htemp.nodeData.key.compareTo(key) == 0) {
                node.nextNode = htemp.nextNode;
                htemp = null;
                return 1;
            } else {
                node = htemp;
                htemp = htemp.nextNode;
            }
        }
        return 0;

    }

    int CLLength(CLType head) {
        CLType htemp;
        int Len = 0;
        htemp = head;
        while (htemp != null) {
            Len++;
            htemp = htemp.nextNode;
        }
        return Len;
    }

    void CLAllNode(CLType head) {
        CLType htemp;
        DATA2 nodeData;
        htemp = head;
        System.out.println("当前链表共有" + CLLength(head) + "个节点。链表所有的数据如下:");
        while (htemp != null) {
            nodeData = htemp.nodeData;
            System.out.println("节点:" + nodeData.key + " " + nodeData.name + " " + nodeData.age);
            htemp = htemp.nextNode;
        }
    }
}

public class LinkedList {
    public static void main(String[] args) {
        CLType node, head = null;
        CLType CL = new CLType();
        String key, findkey;
        Scanner input = new Scanner(System.in);
        System.out.println("链表测试。先输入链表中的数据,格式为:关键字 姓名 年龄");
        do {
            DATA2 nodeData = new DATA2();
            nodeData.key = input.next();
            if (nodeData.key.equals("0")) {
                break;
            } else {
                nodeData.name = input.next();
                nodeData.age = input.nextInt();
                //在链表尾部添加节点
                head = CL.CLAddEnd(head, nodeData);
            }
        } while (true);
        CL.CLAllNode(head);


        System.out.println("演示插入节点,输入插入位置的关键字:");
        findkey = input.next();
        System.out.println("输入插入节点的数据(关键字 姓名 年龄):");
        DATA2 nodeData = new DATA2();
        nodeData.key = input.next();
        nodeData.name = input.next();
        nodeData.age = input.nextInt();
        head = CL.CLInsertNode(head, findkey, nodeData);
        CL.CLAllNode(head);

        System.out.println("演示删除节点,输入删除位置的关键字:");
        key = input.next();
        CL.CLDeleteNode(head, key);
        CL.CLAllNode(head);

        System.out.println("演示在链表中查找,输入查找关键字:");
        key = input.next();
        node = CL.CLFindNode(head, key);
        if (node != null) {
            nodeData = node.nodeData;
            System.out.println("关键字" + key + "对应的节点为" + nodeData.key + " " + nodeData.name + " " + nodeData.age);
        } else {
            System.out.println("在链表中未找到关键字为" + key + "的节点");
        }
    }
}

执行结果

在这里插入图片描述

在这里插入图片描述

C++数据结构-单链表创建     前边我们创建了顺序存储结构的线性表,简称顺序表,顺序表最大的问题是:插入和删除需要移动大量的元素。为了解决 这个问题, 我们引入链式存储结构的线性表,简称链表,链表与顺序表不同,链表的每个结点在内存中是分开存放的,每个结点都包含数据域和指针域:     - 数据域 :存储数据元素本身     - 指针域 :存储相邻结点的地址 链式存储结构的线性表有     - 单链表:每个结点只包含... 阅读详情

相关推荐

数据结构之链表

题目: 1.已知单链表L是一个递增有序链表,设计一个算法,删除表中data值在大于等于min并且小于等于max之间的节点,同时释放删除节点的空间,分析时间复杂度 2.设计一个算法就地逆置单链表 3.已知三个递增有序单链表A,B,C,长度分别为m,n和p设计一个算法使链表A 仅包含三个表中均包含的数据元素,且没有重复,并释放无用节点。限定算法的时间复杂度为O(m+n+p) 链表结构体 typ

epleone的专栏 1054

06 | 链表(上):如何实现LRU缓存淘汰算法?

今天我们来聊聊“链表(Linked list)”这个数据结构。学习链表有什么用呢?为了回答这个问题,我们先来讨论一个经典的链表应用场景,那就是 LRU 缓存淘汰算法。 缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有着非常广泛的应用,比如常见的 CPU 缓存、数据库缓存、浏览器缓存等等。 缓存的大小有限,当缓存被用满时,哪些数据应该被清理出去,哪些数据应该被保留?这就需要缓存淘汰策略来决定。常见的策略有三种:先进先出策略 FIFO(First In,First Out)、最少使用策略 LFU(.

ChinaDragon10的博客 613

避开命令行!在VMware vCenter 8.0图形化界面里搞定SSL证书续期全流程

本文详细介绍了在VMware vCenter 8.0图形化界面中完成SSL证书续期的全流程,包括计算机SSL证书、VMCA根证书和STS证书的管理。通过可视化操作,管理员无需使用命令行即可高效处理证书问题,确保vSphere环境的稳定运行。文章还提供了证书监控与预警配置的实用技巧,帮助用户提前规避证书过期风险。

weixin_27051161的博客 280

[数据结构] 链表(图文超详解讲解)

根据本文对链表的介绍后大家能对链表有更深的理解相信大家在过后时间能够保持求学的态度,我们一起加油!offer拿到手软!对博主感兴趣可以关注博主,我会继续更新博客,努力完善我的文章内容不会辜负大家的期待!

积跬步以至千里 3660

永磁同步电机无传感器控制:HFI与ESMO技术详解

高频注入(HFI)和增强型滑模观测器(ESMO)是现代永磁同步电机(PMSM)无传感器控制的核心技术。HFI通过注入高频信号利用电机凸极效应获取转子位置,而ESMO则通过改进传统滑模观测器,有效抑制抖振并提升动态响应。这两种技术的结合特别适用于零低速区域的位置估计,在工业伺服、电动汽车等领域有广泛应用。方波高频注入作为实现方案之一,具有计算量小、实现简单的特点,配合自适应滤波等信号处理技术,可以在保证精度的同时降低系统成本。

weixin_29183637的博客 353

GD32H7系列SRAM优化配置实战指南

本文详细解析了GD32H7系列MCU的SRAM架构,包括ITCM、DTCM、AXI SRAM等关键内存区域的特点与性能差异。通过实战指南,指导开发者如何通过配置寄存器和链接脚本,优化内存布局以提升系统性能,并重点探讨了DMA操作与CPU缓存一致性的解决方案,帮助充分发挥GD32H7的高性能潜力。

weixin_29169899的博客 518

数据结构-链表

当我们实现了带头双向循环链表的插入和删除数据我们发现,与单链表相比,当前链表无论是在头或者在尾效率都很高,时间复杂度相同为O(N)。这个链表实现也更为简单,所以听起来复杂的链表实现起来并不复杂。

weixin_74312694的博客 1964

MarkDown简介(深度解析MarkDown用法)

欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的快捷键 快捷键 加粗 Ctrl + B 斜体 Ctrl + I...

酷酷的旭 7341

数据结构---单向链表,双向链表,单向环形链表

链表介绍 链表是以节点的方式来存储,是链式存储 每个节点包含 data 域, next 域:指向下一个节点. 如图:发现链表的各个节点不一定是连续存储. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定 修改节点功能 思路(1) 先找到该节点,通过遍历,(2) temp.name = newHeroNode.name ; temp.nickname= newHeroNode.n...

root1994的博客 5841

CCS20实战入门:第一个工程搭建示例

通过实际操作演示如何在ccs20中创建并配置首个开发项目,涵盖环境设置与基础调试步骤,帮助新手快速上手ccs20集成开发环境,提升嵌入式开发效率。

weixin_31185473的博客 884

SquareLine Studio汉化版安装激活全攻略:LVGL嵌入式UI设计从入门到出代码

嵌入式GUI开发中,LVGL作为轻量级开源图形库,广泛应用于STM32、ESP32等MCU平台。可视化设计器通过拖拽生成LVGL代码,大幅提升UI开发效率。SquareLine Studio正是这类工具的代表,支持界面设计、事件绑定与代码导出。其安装、汉化与激活是初学者常见门槛,尤其涉及LVGL版本匹配、字体配置及FreeRTOS移植等关键环节。本文围绕汉化版安装、一个月免费激活码使用及最小可用流程展开,帮助开发者快速上手LVGL界面设计,规避常见环境与集成问题。

weixin_29189987的博客 412

【数据结构】链表的基本概念和操作

int data;//数据域//指针域//别名这里*LinkList表示LNode结构体的指针别名,LinkList p等同于LNode *p。并且要注意指针域next是LNode型。通过结点定义可以看出来链表与顺序表的不同之处:顺序表定义时定义的是一整个顺序表,一整个表就是一个结构体;而链表定义时结构体为一个结点而不是一串链表,结构体之间通过指针相连。int data;//定义前驱后继指针。

Tryagein的博客 1253

手把手教你用微信小程序实现智能硬件音视频通话(含Linux/RTOS适配)

本文详细介绍了如何利用微信小程序硬件框架(WMPF)和音视频SDK,在智能硬件(包括Linux与RTOS设备)上实现音视频通话功能。文章从架构设计、设备端SDK集成、小程序VOIP插件开发到跨平台调试与性能优化,提供了全链路实战指南,帮助开发者打通微信小程序与嵌入式设备间的实时音视频通信。

ooo22的博客 329

数据结构——链表

轻松无痛玩转链表

HZzzzzLu的博客 1万+

SpringBoot集成auth0-jwt插件,实现jwt的token生成、校验,用户登录验证,配置拦截器拦截请求校验token功能

该文章介绍了SpringBoot如何集成auth0-jwt插件,实现jwt的token生成、校验,用户登录验证,配置拦截器拦截请求校验token功能. JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。它以JSON对象的形式存在,并使用数字签名来验证信息的完整性和真实性。JWT由三部分组成,分别是Header、Payload和Signature。

yunnuo的博客 1246

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【数据结构】详细剖析链表,带你实现单链表,双向链表,附链表编程练习题

单链表,带头双向循环链表,链表编程题,顺序表和链表的区别。

林宇恒的博客 3444

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Ada语言的链表操作

Ada语言是一种强类型的结构化编程语言,设计用于支持大型软件项目的开发。它具有良好的可读性和可维护性,适合于实现复杂数据结构。因此,Ada语言非常适合用于链表的实现。在Ada语言中,数据结构可以通过定义记录(record)类型和使用指针来实现。在Ada中,我们可以通过定义一个记录类型来表示链表的节点。每个节点包含一个数据部分和一个指向下一个节点的指针。-- 指向节点的指针-- 存储的数据-- 指向下一个节点的指针end record;```

2501_91290916的博客 1318

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【数据结构】九、链表、双向链表和双向循环链表

链表是一种常见的数据结构,由数据域和指针域组成,在内存中的地址是非连续的,通过指针域就能够依次访问所有节点。相较于数组而言,链表可以高效地添加和删除元素,并且可以根据需要开辟和释放内存空间,因此其对空间的利用非常高效。本章节我将会对链表操作的代码进行讲解,以及一些遇到的问题。

2302_80970336的博客 1458

数据结构和算法学习之路——链表详解(C++版)

数据结构之线性表(链表)详解——(C++语言) The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. —— Bernard Shaw 明白事理的人使自己适应世界;不明事理的人想使世界适应自己。 文章目录数据结构之...

凝望,划过星空的博客 2051

单链表的基本操作

概念:链表是一种、非顺序的存储结构,数据元素的是通过链表中的次序实现的。结构:链表是有各个节点通过指针连接在一起的,每个节点分为数据域和指针域,每个节点的指针域指向下一个节点的地址,最后一个节点的指针域为空。逻辑结构如下图所示物理结构:逻辑结构看起来是连续的,但是由于链表的节点是在堆上开辟的,地址可能连续,也可能不连续。

黄超的博客 3980

【数据结构】链表

链表的概念、分类和实现

wefg1的博客 1296

【数据结构】单链表

在上一期中我们学习了顺序表,但它却有缺点,例如头插或从中间插入效率低等,而链表可以有效的解决这些问题。那么就让我们走进链表的学习。

小王又困了的博客 2655

C语言操作链表详解

C语言操作链表详解链表的概念链表的操作将数据抽象成结构体创建和初始化链表输出链表中存储的数据查找链表中指定位置中存储的数据在链表中插入数据删除指定位置的数据修改制定位置的数据逆序输出链表存储的数据执行结果 在我们学习C语言的前期,每当我们要进行大量数据的读写时,我们都会使用顺序表,也就数组,它的优点很明显,增删读写操作很简单,易于上手。但当我们对数据的存储理解更加深刻时,我们便会逐渐意识到顺序表也不是万能的,它也有它的缺点:顺序表在内存中的存储时,占用一大块连续的空间,但我们实际在使用时,可能并没有那么大的

Violet277的博客 2753

[数据结构]——链表详解

数据结构---链表详解

m0_62023005的博客 4459

c语言单向链表和双向链表的操作

#include<stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> typedef struct student { int num;//学号 char name[10];//姓名 struct student *next;//指针域 }...

wenson的博客 381
上一篇: 顺序表结构的基本操作
下一篇: 栈结构的基本概念及操作
西瓜霜大侠
博客等级 码龄9年 38粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值