首页 > 其他分享 >数据结构--链表(单向链表--有头链表、无头链表)链表的插入、删除、修改、查找

数据结构--链表(单向链表--有头链表、无头链表)链表的插入、删除、修改、查找

时间:2024-08-22 21:52:10浏览次数:10  
标签:Node head -- 有头 next 链表 num 节点

什么是链表?

链表是一种基本的数据结构,用于存储一组数据元素。与数组不同,链表的元素在内存中并不连续存储。链表由一系列节点组成,每个节点包含以下两个主要部分:

1. 数据部分:存储节点所包含的数据。
2. 指针部分:存储指向下一个节点的指针(对于单向链表),或者存储指向前一个节点和下一个节点的指针(对于双向链表)。

链表的主要特点是:
- 动态大小:链表的大小可以根据需要动态增加或减少,而数组的大小在创建时是固定的。
- 插入和删除操作效率高:在链表中进行插入和删除操作时,只需改变指针即可,时间复杂度为 O(1),而在数组中可能需要移动大量元素,时间复杂度为 O(n)。

常见的链表类型包括:
- 单向链表:每个节点只指向下一个节点。
- 双向链表:每个节点指向下一个节点和前一个节点。
- 循环链表:最后一个节点指向头节点,形成一个环。

链表广泛用于实现各种数据结构,如栈、队列等,以及在需要频繁插入和删除操作的场景中。
 

图上可以看到,链表其实就是由一个个的结构体连接而成,用next的指针去指向下一个结构体。

最终指向的为NULL,这就是一个有头的单项链表的表示

代码部分(如果需要源码可以私信我)

一、链表的创建

typedef struct node{
    int data;
    struct node *next;
}Node;

Node *Link_init(){
    Node *head = (Node *)malloc(sizeof(Node));
    if(NULL == head){
        printf("malloc is failed!\n");
    }
    head->data = -1;
    head->next = NULL;
    return head;
}

这里定义了一个名为 node 的结构体,用于表示链

该结构体包含两个成员:

  • int data;:用于存储节点的数据,类型为整数。
  • struct node *next;:指向下一个节点的指针,类型为指向 node 结构体的指针。

这个函数的返回类型是 Node *,即返回一个指向链表头节点的指针。

Node *head = (Node *)malloc(sizeof(Node)):使用 malloc 函数动态分配内存,为一个 Node 类型的节点分配空间,并将其指针赋值给 head 变量。

if(NULL == head) printf("malloc is failed!\n") :检查内存分配是否成功。如果 head 为 NULL,则表示内存分配失败,输出错误信息。

head->data = -1:初始化链表头节点的数据,将其设置为 -1。

head->next = NULL:将链表头节点的 next 指针初始化为 NULL,表示当前节点后面没有其他节点。

return head:返回指向链表头节点的指针。

二、链表的插入

void Link_insert_head(Node *head,int num){
    Node *new = (Node *)malloc(sizeof(Node));
    if(NULL == new){
        printf("new_node malloc is failed!\n");
    }
    new->data = num;
    new->next = NULL;
    //insert
    new->next = head->next;
    head->next = new;
}

当我们插入数据时,首先要定义一个节点(前面提到过链表就是由一个个节点连接而成),还是和前面一样先判断开辟的堆区malloc是否申请成功,初始化new的值new->data就是我们需要插入的数据num,next同样也是指向NULL,最后这两步是整个代码的关键部分,首先我们需要将head->next 赋值给new->next,然后将new赋值给head->next,这样就完成了插入(头插法)。

三、链表的删除

int Linklist_len(Node *head){
    int count = 0;
    Node *p = head->next;
    while(p != NULL){
        count++;
        p = p->next;
    }
    return count;
}

void Linklist_del_num(Node *head,int num){
    if(NULL == head){
        printf("Linklist is error\n");
    }

    Node *p = head;
    Node *q = p->next;
    
    int len = Linklist_len(head);
    for(int i=0;i<len;i++){
        if(q->data == num){
            p->next = q->next;     
        }
         p = p->next;
         q = p->next;
        if(p->next == NULL){
            break;
        }
        
    }
    free(q);
    q = NULL;
}

  1. Linklist_len(Node *head):

    • 该函数计算并返回链表的长度。它接收一个指向链表头节点的指针 head
    • 从 head->next 开始遍历链表(假设头节点不存储有效数据),并统计节点数量。每次遇到一个节点就增加计数 count,直到到达链表尾(即 p 为 NULL)。最终返回计数值 count
  2. Linklist_del_num(Node *head, int num):

    • 此函数用于删除链表中所有值为 num 的节点。
    • 首先检查链表是否为 NULL,若是则输出错误信息。
    • 定义两个指针 p 和 qp 初始化为 headq 初始化为 p->next
    • 通过 Linklist_len 获取链表的长度。在遍历过程中,如果发现节点 q 的数据等于 num,则通过更新指针 p->next 来跳过该节点,从而实现删除。
    • 然而,在代码中存在一些问题:
      • 释放节点 q 的语句不适用于发布已经遍历的节点,因为删除节点后 q 可能带有未定义值(释放已被删除的节点,可能导致错误)。
      • 遍历逻辑可能会导致某些符合条件的节点无法删除,特别是在指针更新后没有正确检查是否到达链表尾的情况。

四、链表修改

void Linklist_change_num(Node *head,int num,int change_num){
    if(NULL == head){
        printf("Linklist is error\n");
    }
    Node *p = head->next;
    for(int i=0;i<Linklist_len(head);i++){
        if(p->data == num){
            p->data = change_num;
        }
        p = p->next;
    }
    
}

该函数 Linklist_change_num 用于遍历一个链表 (head),查找所有值为 num 的节点,并将其数据值更改为 change_num。如果链表为空,函数会打印错误信息。尽管代码包含了逻辑错误(例如,如果 head 为空时会继续执行),并且未考虑链表的头节点的处理。

五、链表查询

void Linklist_search_num(Node *head,int num){
    if(NULL == head){
        printf("Linklist is error\n");
    }
    Node *p = head->next;
    for(int i=0;i<Linklist_len(head);i++){
        if(p->data == num){
            printf("search num is :%d\n",p->data);
        }
        if(p->next != NULL){
             p = p->next;
        }
    } 

}

该函数 `Linklist_search_num` 用于在链表中查找值为 `num` 的节点。如果链表为空,函数会打印错误信息。遍历链表时,如果找到 `data` 等于 `num` 的节点,就打印该数据值。函数还确保在遍历时不会访问空指针,但有逻辑错误,可能导致每个节点都被检查。具体来说,在循环中,`p` 的更新条件可能导致最后一个节点不会被检查。
 

标签:Node,head,--,有头,next,链表,num,节点
From: https://blog.csdn.net/fzxznb/article/details/141438255

相关文章

  • C++设计模式1:单例模式(懒汉模式和饿汉模式,以及多线程问题处理)
    饿汉单例模式        程序还没有主动获取实例对象,该对象就产生了,也就是程序刚开始运行,这个对象就已经初始化了。 classSingleton{public: ~Singleton() { std::cout<<"~Singleton()"<<std::endl; } staticSingleton*get_instance() { return&sin......
  • Towards Mitigating ChatGPT’s Negative Impact on Education: Optimizing Question
    文章目录题目摘要引言概述实验结果结论和未来工作题目减轻ChatGPT对教育的负面影响:通过布鲁姆分类法优化问题设计论文地址:https://ieeexplore.ieee.org/document/10223662摘要    生成文本AI工具在回答问题方面的流行引发了人们对其可能对学生学业成......
  • Can Autograding of Student-Generated Questions Quality by ChatGPT Match Human Ex
    文章目录题目摘要引言相关工作方法讨论与启示结论题目ChatGPT对学生生成问题质量的自动评分能否与人类专家媲美?论文地址:https://ieeexplore.ieee.org/document/10510637摘要    学生生成问题(SGQ)策略是一种有效的教学策略,可培养学生的高阶认知和批判......
  • HTC 10 刷系统 LineageOS 19.1 Android 12
    解锁手机解锁会导致数据全部清除,注意保存Bootloader解锁,S-ON可以不用解锁(好像可以绕过解锁安装twrp,暂时没尝试)HTC官方UnlockBootloaderHTCDesire20pro可以不通过官方网站解锁adbrebootbootloader#进入bootloadersudofastbootflashingunlock#选择UNLOC......
  • 手机轰炸机 短信轰炸 可匣 二90二1243交流
    使用fiddler抓包获取到了100+个发送短信验证的接口使用自己手机试了一下速度非常快。因为是同时迸发,所以导致手机短信量一瞬间到了100+但是会导致一个问题,就是无感知情况于是调整接口请求方式,设置异步请求,间隔3s钟,这次以后会达到一个比较好的效果没办法上传视频只能看......
  • 元宇宙虚拟展厅_元宇宙线上展馆制作成本有哪些?
    电子商务热潮的日益普及,让更多企业开始寻找具有创新性的方式来向客户展示他们的产品和服务。而元宇宙中的虚拟展厅也为企业提供了一个独特的机会,作为帮助企业展示其产品和服务特色的平台,元宇宙越发地受欢迎。不过在元宇宙中制作虚拟展厅的成本是由多种因素组成的,本文聊聊元宇宙虚......
  • 防抖:解决频繁操作的小技巧!
    ......
  • 声音克隆GPT-SoVITS 2.0软件和详细的使用教程!
    天命人,请允许我先蹭个热点!  原始声音:播放克隆声音:播放 文章写了一半,被《黑神话悟空》刷屏了。突发奇想,用里面的声音来做个素材试试看。B站捞了一点声音素材,随便剪一剪,训练一把过,没有调优,就直接拿来用了。情绪还差点意思,音色克隆的还不错。......
  • YC327B [ 20240821 CQYC NOIP 模拟赛 T2 ] 括号串(bracket)
    题意给定\(S\in\{(,),?\}\)。定义深度为括号嵌套的子序列的最大长度除以\(2\)。求出将\(?\)替换为括号的所有括号串的深度之和,对\(998244353\)取模。\(n\le10^6\)。Sol考虑如何把每次贡献只计算一次。不难想到在括号的中心点计算。可以发现,若当前左右括号......
  • 测试基础
    白盒测试怎么做:1.静态扫描2.动态扫描,构造测试数据去检查。语句覆盖--覆盖所有代码3.判定覆盖每个判定条件,每个判定都需真假值4.条件覆盖每个条件,都需要有一个真假值5.判定/条件覆盖6.组合覆盖,条件之间的组合场景7.路径覆盖---后面的黑盒流程分析法安全测试我们常用的方法......