【数据结构】链表C++编写的,它定义了一个链表,并实现了一些基本的链表操作,如创建新节点、插入节点、清空链表、输出链表以及查找节点

news2024/9/22 15:34:54

// 引入标准输入输出流库,用于输出操作  
#include <iostream>  
// 引入标准库中的stdlib,包含了rand()函数和其他相关函数  
#include <cstdlib>  
// 引入标准库中的time,包含了time()函数和其他相关函数  
#include <ctime>  
  
// 定义常量DL为3,表示链表每个节点占用的字符宽度  
#define DL 3  
  
// 使用宏定义一个字符串化运算符,用于将数字转化为字符串  
#define STR(n) #n  
// 使用宏定义一个格式化字符串,用于输出特定长度的整数,例如"%3d"表示输出的整数占用三个字符长度  
#define DIGIT_LEN_STR(n) "%" STR(n) "d"  
  
// 定义一个结构体Node,表示链表中的节点  
struct Node {  
    int data;  // 节点的数据域,存储节点的值  
    Node* next;  // 指向下一个节点的指针  
};  
  
// 定义一个函数,用于创建一个新的节点,并返回该节点的指针  
Node* getNewNode(int val) {  
    // 动态分配一个新的Node内存空间,并返回其指针  
    Node* p = new Node;  
    // 设置新节点的数据域为传入的值  
    p->data = val;  
    // 将新节点的next指针设置为nullptr,表示该节点为链表的末尾  
    p->next = nullptr;  
    // 返回新节点的指针  
    return p;  
}  
  
// 定义一个函数,用于在链表的指定位置插入一个新的节点  
Node* insert(Node* head, int pos, int val) {  
    // 创建一个新的头节点new_head,并创建一个新的节点node  
    Node new_head, *p = &new_head, *node = getNewNode(val);  
    // 将new_head的next指针指向当前的head,形成一个新的链表  
    new_head.next = head;  
    // 通过循环移动p指针到指定位置的前一个节点  
    for (int i = 0; i < pos; i++) {  
        p = p->next;  
    }  
    // 将node的next指针指向p的下一个节点,实现插入操作  
    node->next = p->next;  
    // 将p的下一个节点设置为node,完成插入操作  
    p->next = node;  
    // 返回新的链表的头节点的指针  
    return new_head.next;  
}  
  
// 定义一个函数,用于清空链表中的所有节点,释放其内存空间  
void clear(Node* head) {  
    // 如果链表为空,则直接返回  
    if (head == nullptr) {  
        return;  
    }  
    // 定义两个指针p和q,p用于遍历链表,q用于保存下一个节点  
    Node *p = head, *q;  
    // 当p非空时,执行以下操作  
    while (p) {  
        // 保存p的下一个节点为q  
        q = p->next;  
        // 释放p的内存空间  
        delete p;  
        // 将p移动到下一个节点  
        p = q;  
    }  
}  
  
// 输出链表函数开始  
void output_linklist(Node* head, int flag = 0) {  
    // 初始化计数器n为0  
    int n = 0;  
      
    // 遍历链表,计算链表中节点的数量,并累加到n中  
    for (Node* p = head; p; p = p->next) {  
        n += 1;  
    }  
      
    // 输出每行的前缀,表示节点的位置,使用特定长度的整数格式化字符串输出n的值,并在后面加上空格  
    for (int i = 0; i < n; i++) {  
        std::cout << i << "  ";  
    }  
      
    // 输出换行符,表示一行的结束  
    std::cout << std::endl;  
      
    // 遍历链表,输出每个节点的值和它连接的下一个节点,使用字符串化运算符将整数转化为字符串并输出,最后输出箭头符号"->"表示连接关系  
    for (Node* p = head; p; p = p->next) {  
        std::cout << p->data << "->";  
    }  
      
    // 输出换行符,表示一行的结束  
    std::cout << std::endl;  
      
    // 如果flag等于0,则输出一个额外的换行符  
    if (flag == 0) {  
        std::cout << std::endl;  
    }  
      
    // 输出链表函数结束  
}
// 定义一个函数,用于在链表中查找指定值的节点  
int find(Node* head, int val) {  
    // 定义一个指针p,指向链表的头节点  
    Node* p = head;  
    // 初始化计数器n为0  
    int n = 0;  
    // 遍历链表,直到p为空(链表结束)  
    while (p) {  
        // 如果当前节点的值等于目标值val  
        if (p->data == val) {  
            // 调用output_linklist函数输出整个链表,参数为head和1(表示需要输出找到的节点)  
            output_linklist(head, 1);  
            // 计算找到的节点在链表中的位置,长度为n*(DL+2)+2  
            int len = n * (DL + 2) + 2;  
            // 输出一些空格,用于画出一个矩形框来标记找到的节点  
            for (int i = 0; i < len; i++) std::cout << " ";  
            // 输出一个竖线,用于标记找到的节点在矩形框中的位置  
            std::cout << "^\n";  
            // 再输出一些空格,用于画出矩形框的底部  
            for (int i = 0; i < len; i++) std::cout << " ";  
            // 输出一个竖线,用于标记矩形框的底部  
            std::cout << "|\n";  
            // 如果找到目标值,则返回1,表示成功找到  
            return 1;  
        }  
        // 每遍历一个节点,计数器n加1  
        n += 1;  
        // 将指针p移动到下一个节点  
        p = p->next;  
    }  
    // 如果未找到目标值,则返回0,表示未找到  
    return 0;  
}  
  
// 主函数开始  
int main() {  
    // 使用当前时间作为随机数种子,保证每次运行程序时生成的随机数不同  
    srand(time(0));  
    // 定义常量MAX_OP为7  
#define MAX_OP 7  
    // 初始化一个空的链表,头节点为nullptr  
    Node* head = nullptr;  
    // 循环执行MAX_OP次操作,每次插入一个随机位置的随机值节点到链表中  
    for (int i = 0; i < MAX_OP; i++) {  
        // 生成一个随机位置(范围为i+1,保证位置从0开始)和一个随机值(范围为0-99)  
        int pos = rand() % (i + 1), val = rand() % 100;  
        // 输出插入操作的信息  
        std::cout << "insert " << val << " at " << pos << " to linklist" << std::endl;  
        // 将新节点插入到指定位置,并更新头节点指针head  
        head = insert(head, pos, val);  
        // 输出当前链表的内容  
        output_linklist(head);  
    }  
    // 从标准输入中读取一个整数val  
    int val;  
    while (std::cin >> val) {  
        // 在链表中查找值为val的节点,如果没有找到则返回0,表示未找到  
        if (!find(head, val)) {  
            // 如果未找到,则输出not found信息  
            std::cout << "not found" << std::endl;  
        }  
    }  
    // 清空链表,释放内存空间  
    clear(head);  
    // 主函数结束,返回0表示程序正常退出  
    return 0;  
}

这段代码实现了一个简单的链表数据结构,并提供了插入、查找和输出链表的功能。

首先,代码中定义了一些宏,其中DL被定义为3,用于表示链表节点中的整数占用的位数。STR(n)用于将一个数值表达式n转换为字符串,DIGIT_LEN_STR(n)用于计算一个整数的位数并转换为字符串。

接下来,定义了一个结构体Node,表示链表的节点。每个节点包含一个整数数据成员data和一个指向下一个节点的指针next

然后,定义了一个函数getNewNode(int val),用于创建一个新的节点,并初始化其数据成员为给定的值val,并将指针next初始化为nullptr

接下来,定义了函数insert(Node* head, int pos, int val),用于在链表中插入一个新的节点。该函数首先创建一个新的节点,然后使用一个临时头节点new_head来处理插入位置。它通过循环遍历链表,找到指定位置的前一个节点,然后将新节点插入到该节点之后。最后返回更新后的链表头节点。

接下来,定义了函数clear(Node* head),用于清空链表。该函数通过遍历链表并逐个删除节点来释放内存空间。

接下来,定义了函数output_linklist(Node* head, int flag = 0),用于输出链表的内容。该函数首先计算链表的长度,然后依次输出每个节点的数据和指向下一个节点的箭头符号。如果flag的值为0,则在最后输出一个换行符。

接下来,定义了函数find(Node* head, int val),用于在链表中查找指定的值。该函数遍历链表,如果找到了与给定值相等的节点,则输出该节点及其后的所有节点,并在其前面输出一个标记符号"^"和"|",然后返回1表示找到了目标值。如果遍历完整个链表都没有找到目标值,则返回0表示未找到。

最后,在主函数中,首先使用随机数生成器初始化随机数种子,然后通过循环随机生成插入操作和输出操作。每次循环中,随机生成一个插入位置和插入的值,然后调用insert函数将新节点插入到指定位置,并输出更新后的链表内容。循环结束后,从标准输入中读取一个整数,然后调用find函数在链表中查找该整数。如果找到了目标值,则返回1;否则返回0,表示未找到。

总结起来,这段代码实现了一个简单的链表数据结构,并提供了插入、查找和输出链表的功能。

运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/986826.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】高级IO --- Reactor网络IO设计模式

人其实很难抵制诱惑&#xff0c;人只能远离诱惑&#xff0c;所以千万不要高看自己的定力。 文章目录 一、LT和ET模式1.理解LT和ET的工作原理2.通过代码来观察LT和ET工作模式的不同3.ET模式高效的原因&#xff08;fd必须是非阻塞的&#xff09;4.LT和ET模式使用时的读取方式 二…

正反向代理理解

正向代理&#xff08;Forward Proxy&#xff09;和反向代理&#xff08;Reverse Proxy&#xff09;是两种用于网络通信的代理服务器&#xff0c;它们分别用于不同的场景和目的。 正向代理&#xff08;Forward Proxy&#xff09;&#xff1a; 正向代理是位于客户端和目标服务器…

球谐函数在环境光照中的使用原理

在三维空间中如何对场景光照进行球谐函数展开 图形学论文解析与复现【Spherical Harmonic Lighting:The Gritty Details】 首先&#xff0c;对场景中某像素点的漫反射光照进行计算。 L ( p , w o ) ∫ Ω L ( w i ) n ⋅ w i d w i L(p,w_o) \int_{\Omega}L(w_i)n\cdot w_i…

cad打印样式丢失怎么处理?

一提到CAD软件&#xff0c;我相信很多朋友都特别熟悉&#xff0c;因为在工作中很多的图纸设计都有它的功劳&#xff0c;经常从事cad设计的朋友对于cad打印样式都非常地精通了&#xff0c;在打印样式里包括了图纸的颜色、线条等&#xff0c;由于各种原因cad打印样式丢失了&#…

自行实现字符串转浮点数函数atof()

【重复造轮子的原因】 尽管atof是标准C中自带的函数,用于将字符串转为浮点数,但是在某些环境下有可能没法使用的(例如CUDA环境中,没有atof函数,但是math.h可以使用),因此自行实现。 【通过的测试用例】 【实现的代码】 #include <stdio.h> #include <math.h…

linux(rhel7)内核参数优化

内核参数 Linux sysctl.d 配置内核参数 rhel7中sysctl.d和sysctl.conf的执行顺序 执行顺序&#xff1a; sysctl.d > /etc/sysctl.conf sysctl.d的执行顺序&#xff1a; /etc/sysctl.d/run/sysctl.d/usr/local/lib/sysctl.d/usr/lib/sysctl.d/lib/sysctl.d/ 对于不同目录下…

交换排序——冒泡排序、快速排序

交换排序就是通过比较交换实现排序。分冒泡排序和快速排序两种。 一、冒泡排序&#xff1a; 1、简述 顾名思义就是大的就冒头&#xff0c;换位置。 通过多次重复比较、交换相邻记录而实现排序&#xff1b;每一趟的效果都是将当前键值最大的记录换到最后。 冒泡排序算法的原…

如何关闭一个tcp连接 阻塞和等待的区别 b树查找的过程

如何关闭一个 TCP 连接 可能大家第一反应是「杀掉进程」不就行了吗&#xff1f; 是的&#xff0c;这个是最粗暴的方式&#xff0c;杀掉客户端进程和服务端进程影响的范围会有所不同&#xff1a; • 在客户端杀掉进程的话&#xff0c;就会发送 FIN 报文&#xff0c;来断开这个客…

企业网络小实验-MUX-Vlan(NAT)

路漫漫其修远兮&#xff0c;吾将上下而求索 直接上实验 实验说明 模拟公司的部门实验&#xff0c; &#xff08;1&#xff09;公司主机如图所示&#xff0c;配置DNS服务器&#xff0c;配置NAT地址转换&#xff08;使用easy-ip的形式&#xff09;访问外网。 &#xff08;2&…

基于SSM的家政服务网站

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

ARM架构之寄存器

CPU进行数据运算和逻辑运算 寄存器 概念 寄存器是处理器内部的存储器&#xff0c;没有地址 作用 一般用于暂时存放参与运算的数据和运算结果 分类 包括通用寄存器、专用寄存器、控制寄存器 C语言中四种存储类型的详解 一、auto存储类型 用auto存储类型说明的变量都是局部于…

单片机有哪些分类?

单片机有哪些分类? 1.AVR单片机-----速度快&#xff0c;一个时钟周期执行一条指令&#xff0c;而普通的51单片机需要12个时钟周期执行一条指令。当然&#xff0c;Atmel公司出品的AT89LP系列单片机也是一个时钟执行一条指令&#xff0c;但目前还未普及。AVR单片机比51单片机多…

2023年全国大学生数学建模B题

多波束测线问题 1.问题提出 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀 速直线传播&#xff0c;在不同界面上产生反射&#xff0c;利用这一原理&#xff0c;从测量船换能器垂直向海底发射声波信号&#xff0c;并记录从声波发射到信号接…

显示器配置信息删除

显示器配置信息删除 1 介绍2 操作参考 1 介绍 笔记本屏幕坏了&#xff0c;手头的拓展显示器都是配置成拓展显示&#xff0c;需要先找一台没配置过的显示器将系统中显示器配置信息删除&#xff0c;这样就能复制屏幕显示到拓展屏幕上了。 2 操作 Windows 的显示器配置位于注册…

go语言基本操作---六

并发编程 并行&#xff1a;指在同一时刻&#xff0c;有多条指令在多个处理器上同时执行。 并发&#xff1a;指在同一时刻只能有一条指令执行&#xff0c;但是多个进程指令被快速的轮换执行&#xff0c;使得在宏观上具有多个进程同时执行的效果&#xff0c;但在微观上并不是同时…

机器学习——逻辑回归(LR)

机器学习——逻辑回归&#xff08;LR&#xff09; 文章目录 前言一、原理介绍二、代码实现2.2. 混淆矩阵2.3. 分类报告2.4. 可视化分类结果 三、额外&#xff08;先划分数据集再降维与先降维再划分数据集&#xff09;3.1. 先划分数据集再降维3.2. 先降维再划分数据集3.3. 比较 …

2023数学建模国赛选题建议及BC题思路

大家好呀&#xff0c;全国大学生数学建模竞赛今天下午开赛啦&#xff0c;在这里先带来初步的选题建议及思路。 目前团队正在写B题和C题完整论文&#xff0c;后续还会持续更新哈&#xff0c;以下只是比较简略的图文版讲解&#xff0c;团队目前正在写B、C题完整论文&#xff0c;…

【C语言】进阶——深度剖析数据的存储

目录 1.数据类型 &#x1f43b;整型分类 2.整型在内存中的存储 &#x1f43b;2.1原码&#xff0c;反码&#xff0c;补码 &#x1f43b;2.2大小端介绍 3.浮点数在内存中的存储 1.数据类型 使用不同类型开辟内存空间的大小不同&#xff08;大小决定了使用范围&#xff09…

jmeter系列-测试计划详细介绍(3)

测试计划的作用 测试计划描述了 Jmeter 在执行时&#xff0c;一系列的步骤一个完整的测试计划包含了一个或多个【线程组、逻辑控制器、采样器、监听器、定时器、断言和配置元素】 Jmeter原件和组件的介绍 基本元件的介绍 多个类似功能组件的 容器&#xff08;类似于类&…

第四节唯物辩证法(两大总特征)

新旧事物与时间无关&#xff0c;与是否合乎历史方向有关&#xff0c;如有些00后思想可能落后与80后