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

这篇具有很好参考价值的文章主要介绍了【数据结构】链表C语言编写的,它定义了一个链表,并实现了一些基本的链表操作,如创建新节点、插入节点、清空链表、输出链表以及查找节点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

#include <stdio.h>    // 引入标准输入输出库,用于输入输出操作  
#include <stdlib.h>   // 引入标准内存分配库,用于动态内存分配  
#include <time.h>     // 引入标准时间库,用于使用随机数生成函数  
  
// 定义常量DL为3,未在后续代码中使用,可能为误提交或者待使用  
#define DL 3  
// 定义宏STR,将参数转换为对应的字符串表示  
#define STR(n) #n  
// 定义宏DIGIT_LEN_STR,将参数作为格式字符串与一个整数结合,生成对应的格式化字符串  
#define DIGIT_LEN_STR(n) "%" STR(n) "d"  
  
// 定义一个结构体Node,表示链表中的一个节点  
typedef struct Node {  
    int data;          // 节点的数据部分,此处为整型  
    struct Node *next;  // 节点的下一个节点的指针  
} Node;  
  
// 定义一个函数getNewNode,用于创建一个新的节点并返回其指针  
Node *getNewNode(int val) {  
    // 通过malloc动态分配内存,创建新节点  
    Node *p = (Node *)malloc(sizeof(Node));  
    // 设置新节点的数据部分  
    p->data = val;  
    // 设置新节点的下一个节点为NULL  
    p->next = NULL;  
    // 返回新节点的指针  
    return p;  
}  
  
// 定义一个函数insert,用于在链表的指定位置插入一个新的节点  
Node *insert(Node *head, int pos, int val) {  
    // 创建一个新的头节点new_head,用于保存插入新节点后的链表头  
    Node new_head, *p = &new_head, *node = getNewNode(val);  
    // 将new_head的next指向原链表的头节点head  
    new_head.next = head;  
    // 在链表中找到指定位置的前一个节点,此处使用了一个for循环  
    for (int i = 0; i < pos; i++) p = p->next;  
    // 将新节点插入到指定位置,此处涉及链表的操作  
    node->next = p->next;  
    p->next = node;  
    // 返回新链表的头节点new_head的next指针,即插入新节点后的链表头  
    return new_head.next;  
}  
  
// 定义一个函数clear,用于清空链表中的所有节点,释放其内存空间  
void clear(Node *head) {  
    // 如果链表为空,则直接返回,无需进行任何操作  
    if (head == NULL) return ;  
    // 遍历链表,逐个释放节点的内存空间,直至链表末尾  
    for (Node *p = head, *q; p; p = q) {  
        q = p->next;   // q保存下一个节点,为下一次循环准备  
        free(p);       // 释放当前节点的内存空间  
    }  
    return ;           // 所有节点已经释放完毕,函数结束返回  
}
// 输出链表的函数,参数为链表的头节点和标记flag,默认为0  
void output_linklist(Node *head, int flag = 0) {  
    // 初始化节点计数为0  
    int n = 0;  
    // 遍历链表,计算链表的长度  
    for (Node *p = head; p; p = p->next) n += 1;  
    // 根据DL宏定义的长度,打印数字表示的索引和空格  
    for (int i = 0; i < n; i++) {  
        printf(DIGIT_LEN_STR(DL), i);  
        printf("  ");  
    }  
    // 打印换行符  
    printf("\n");  
    // 遍历链表,打印每个节点的值和箭头符号  
    for (Node *p = head; p; p = p->next) {  
        printf(DIGIT_LEN_STR(DL), p->data);  
        printf("->");  
    }  
    // 再打印换行符  
    printf("\n");  
    // 如果flag为0,打印额外的换行符  
    if (flag == 0) printf("\n\n");  
    // 函数结束并返回  
    return ;  
}  
  
// 在链表中查找值的函数,参数为链表的头节点和要查找的值  
int find(Node *head, int val) {  
    // 初始化指针p为链表的头节点  
    Node *p = head;  
    // 初始化计数为0  
    int n = 0;  
    // 遍历链表,查找值为val的节点  
    while (p) {  
        // 如果找到值为val的节点  
        if (p->data == val) {  
            // 输出链表,标记为1,表示找到了值  
            output_linklist(head, 1);  
            // 计算打印的空格长度,为节点计数乘以每个节点的长度加上两个空格的长度再加两个空格的长度  
            int len = n * (DL + 2) + 2;  
            // 在打印的结果下方打印len个横线" -"  
            for (int i = 0; i < len; i++) printf(" ");  
            // 在打印的横线上方打印"^"符号  
            printf("^\n");  
            // 在打印的横线下方再打印len个横线" |"  
            for (int i = 0; i < len; i++) printf(" ");  
            // 在最下方打印"|"符号  
            printf("|\n");  
            // 返回1,表示找到了值为val的节点  
            return 1;  
        }  
        // 如果没找到,计数加1并移动到下一个节点  
        n += 1;  
        p = p->next;  
    }  
    // 如果遍历完链表都没找到值为val的节点,返回0,表示没找到  
    return 0;  
}
// 程序的主函数开始  
int main() {  
  
    // 使用当前时间作为随机数生成器的种子,这样每次运行程序时,生成的随机数都会不同  
    srand(time(0));  
  
    // 定义常量MAX_OP为7,这可能是一个操作的上限或者是要插入的节点数量  
    #define MAX_OP 7  
  
    // 创建一个指向Node类型的指针head,并将其初始化为NULL,这是链表的头节点  
    Node *head = NULL;  
  
    // 循环MAX_OP次,进行MAX_OP次操作  
    for (int i = 0; i < MAX_OP; i++) {  
  
        // 随机生成一个在0到i之间的位置,pos代表要插入新节点的位置  
        int pos = rand() % (i + 1);  
  
        // 随机生成一个0到99之间的值,val代表要插入的新节点的值  
        int val = rand() % 100;  
  
        // 打印出要进行的操作,即将val插入到pos位置  
        printf("insert %d at %d to linklist\n", val, pos);  
  
        // 调用insert函数,将新节点插入到链表的指定位置,并更新head为新的头节点  
        head = insert(head, pos, val);  
  
        // 调用output_linklist函数,打印出当前的链表状态  
        output_linklist(head);  
    }  
  
    // 从标准输入读取一个整数val,如果读取失败(输入的不是整数),则返回-1,所以~scanf("%d", &val)会变成-1的补码,是一个很大的数  
    int val;  
    while (~scanf("%d", &val)) {  
  
        // 调用find函数在链表中查找val,如果没找到,则返回0  
        if (!find(head, val)) {  
  
            // 如果没找到,打印"not found"  
            printf("not found\n");  
        }  
    }  
  
    // 调用clear函数,清除链表中的所有节点,释放其内存空间  
    clear(head);  
  
    // 返回0,表示程序正常结束  
    return 0;  
}

这段代码是用C语言编写的,它定义了一个链表,并实现了一些基本的链表操作,如创建新节点、插入节点、清空链表、输出链表以及查找节点。以下是每段代码的详细解释:

  1. 文件注释:

    • 这段代码是一个文件注释
  2. 包含头文件:

    • #include <stdio.h> 和 #include <stdlib.h>:这两个头文件包含了标准输入输出库和标准库,用于进行输入输出和内存分配等操作。
    • #include <time.h>:这个头文件包含了关于时间的函数,srand(time(0)) 用于设置随机数生成器的种子。
  3. 宏定义:

    • #define DL 3:这个宏定义了一个常量 DL,它的值为3。
    • #define STR(n) #n 和 #define DIGIT_LEN_STR(n) "%" STR(n) "d":这两个宏用于生成字符串表示的整型常量。例如,DIGIT_LEN_STR(3) 会被替换为 "%3d"
  4. 结构体 Node 的定义:

    • typedef struct Node { int data; struct Node *next; } Node;:这定义了一个名为 Node 的结构体类型,它有两个成员,一个 data 用于存储节点数据,一个 next 用于指向下一个节点。
  5. 函数 getNewNode 的定义:

    • Node *getNewNode(int val) { Node *p = (Node *)malloc(sizeof(Node)); p->data = val; p->next = NULL; return p; }:这个函数用于创建一个新的节点,它接收一个整型参数 val,创建一个新的 Node 类型的对象,将 val 赋值给新节点的 data 成员,将新节点的 next 设置为 NULL,并返回新创建的节点的指针。
  6. 函数 insert 的定义:

    • Node *insert(Node *head, int pos, int val) { Node new_head, *p = &new_head, *node = getNewNode(val); new_head.next = head; for (int i = 0; i < pos; i++) p = p->next; node->next = p->next; p->next = node; return new_head.next; }:这个函数用于在链表的指定位置插入一个新的节点,它接收三个参数,链表的头节点 head、要插入的位置 pos 和要插入的值 val。它首先创建一个新的头节点 new_head,然后通过调用 getNewNode 创建一个新的节点,将新节点的值设置为 val。然后通过循环找到要插入的位置,最后将新节点插入到链表的指定位置,并返回新的头节点的指针。
  7. 函数 clear 的定义:

    • void clear(Node *head) { if (head == NULL) return ; for (Node *p = head, *q; p; p = q) { q = p->next; free(p); } return ; }:这个函数用于清空链表,它接收一个参数,链表的头节点 head。它首先检查链表是否为空,如果是则直接返回。然后通过循环遍历链表,释放每个节点的内存空间。
  8. 函数 output_linklist 的定义:文章来源地址https://www.toymoban.com/news/detail-704314.html

    • void output_linklist(Node *head, int flag = 0) { int n = 0; for (Node *p = head; p; p = p->next) n += 1; for (int i = 0; i < n; i++) { printf(DIGIT_LEN_STR(DL), i); printf(" "); } printf("\n"); for (Node *p = head; p; p = p->next) { printf(DIGIT_LEN_STR(DL), p->data); printf("->"); } printf("\n"); if (flag == 0) printf("\n\n"); return ; }:这个函数用于输出链表,它接收两个参数,链表的头节点 head 和一个标记 flag。它首先计算链表的长度,然后根据长度打印出相应数量的数字和空格,然后打印出链表中的所有元素和箭头符号。如果 flag 为0,则在打印完链表

到了这里,关于【数据结构】链表C语言编写的,它定义了一个链表,并实现了一些基本的链表操作,如创建新节点、插入节点、清空链表、输出链表以及查找节点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言数据结构-双向链表

    带头链表的头结点,实际是\\\"哨兵位\\\",哨兵位节点不存储任何有效元素,只是站在这里\\\"放哨的\\\". 哨兵位的意义:遍历循环链表避免死循环. 笔者在删除,插入数据时,画好图后,也好了代码,但是在调试中多次出现 代码位置出错 ,导致写的代码的含义不符合预期. 所以说思路一定要清晰

    2024年02月04日
    浏览(16)
  • 数据结构链表(C语言实现)

            机遇对于有准备的头脑有特别的亲和力。本章将讲写到链表其中主要将写到单链表和带头双向循环链表的如何实现。    话不多说安全带系好,发车啦 (建议电脑观看) 。 附:红色,部分为重点部分;蓝颜色为需要记忆的部分(不是死记硬背哈,多敲);黑色加粗

    2024年02月10日
    浏览(22)
  • 双向链表(数据结构)(C语言)

    目录 概念 带头双向循环链表的实现 前情提示 双向链表的结构体定义 双向链表的初始化 关于无头单向非循环链表无需初始化函数,顺序表、带头双向循环链表需要的思考 双向链表在pos位置之前插入x 双向链表的打印 双链表删除pos位置的结点 双向链表的尾插 关于单链表的尾

    2024年02月04日
    浏览(37)
  • C语言实现链表--数据结构

    魔王的介绍:😶‍🌫️一名双非本科大一小白。 魔王的目标:🤯努力赶上周围卷王的脚步。 魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥 ❤️‍🔥大魔王与你分享:很喜欢宫崎骏说的一句话:“不要轻易去依赖一个人,它会成为你的习惯当分别来临,你失去的不是某个人而是你精

    2024年02月02日
    浏览(12)
  • 双向链表--C语言实现数据结构

    本期带大家一起用C语言实现双向链表🌈🌈🌈 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的;简单来说,线性表的链式存储结构生成的表,称作“链表”。 每个元素本身由两部分组成: 1、本身的信息,称

    2024年02月04日
    浏览(30)
  • Go语言数据结构(一)双向链表

    Go语言中list容器定义在\\\"container/list\\\"包中,实现了一个双向链表。本文第一部分总结源码包中的方法,第二部分展示使用list包的常见示例用法以及刷题时的用法。 食用指南:先看第二部分的常用示例用法然后再用到时在第一部分找对应的方法。 更多内容以及其他Go常用数据结

    2024年01月19日
    浏览(17)
  • 数据结构——单向链表(C语言版)

    在数据结构和算法中,链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。在C语言中,我们可以使用指针来实现单向链表。下面将详细介绍如何用C语言实现单向链表。 目录 1. 定义节点结构体 2. 初始化链表 3. 插入节点 4. 删除节点

    2024年03月24日
    浏览(20)
  • <数据结构> 链表 - 单链表(c语言实现)

    哨兵位结点也叫哑节点。哨兵位结点 也是头结点 。该节点 不存储有效数据,只是为了方便操作 (如尾插时用带哨兵位的头结点很爽,不需要判空)。 有哨兵位结点的链表,第一个元素应该是链表第二个节点(head - next,head为哨兵位结点)对应的元素。 有哨兵位结点的链表

    2023年04月11日
    浏览(13)
  • 数据结构——双向链表(C语言版)

    上一章: 数据结构——单向链表(C语言版)-CSDN博客 目录 什么是双向链表? 双向链表的节点结构 双向链表的基本操作 完整的双向链表示例 总结 什么是双向链表? 双向链表是一种常见的数据结构,它由一系列节点组成,每个节点包含两个指针:一个指向前一个节点,一个

    2024年03月26日
    浏览(24)
  • C语言进阶——数据结构之链表(续)

    hello,大家好呀,我是Humble,本篇博客承接之前的 C语言进阶——数据结构之链表 的内容 (没看过的小伙伴可以从我创建的专栏C语言进阶之数据结构 找到那篇文章并阅读后在回来哦~) ,上次我们重点说了链表中的 单链表 ,即 不带头单向不循环链表 还说到了链表的分类虽

    2024年01月25日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包