数据结构(二)单链表

news2024/11/17 14:31:44

一、链表

(一)概念

逻辑结构:线性
存储结构:链式存储,在内存中不连续

分为有头链表和无头链表
同时又细分为单向、循环、双向链表

(二)有头单向链表示意图

以下数据及地址只是为了方便理解设置
在这里插入图片描述

(三)操作

1. 节点的结构体定义:

① 定义:

typedef struct node
{
    int data; //保存数据
    struct node* next;  //记录下一节点的地址,注意此时指针类型不能定义为nd_t*
}nd_t;

② 注意点:

  1. 定义结构体成员时,指针的类型此时不能使用nd_t定义。

2. 创建链表

(1) 函数声明

create_list(nd_t **phead,int num);

该函数需要在内存中申请一块nd_t类型大小的空间,并将其地址返回给main函数中用户定义的指针中;
num是用来初始化这块空间中数据域的值。

(2)注意点:
  1. 必须传入二级指针
  2. phead不能为空,即不能传一个NULL作为形参,后面需要对phead取值
  3. 需要检查是否申请内存成功
(3)示意图

在这里插入图片描述

(4)代码实现
//创建节点
create_list(nd_t **phead,int num){
    if(NULL==phead){
        printf("传入指针为NULL");
    }
    //*phead可以为空,即main函数中的phead可以是一个空指针
    //但是phead不能为空,即不能传一个NULL作为形参
    *phead=(nd_t *)malloc(sizeof(nd_t));
    if(NULL==*phead){
        printf("申请空间失败!\n");
        return -1;
    }
    //初始化
    (*phead)->data=num;
    (*phead)->next=NULL;
    return 0;
}

3. 清空

(1) 函数声明

int clean_list(nd_t *phead);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现
int clean_list(nd_t *phead){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(NULL==phead->next){
        printf("表为空\n");
        return -1;
    }
    nd_t *ptemp=NULL;
    //使用头删清空
    while(NULL!=phead->next)
    {
        ptemp=phead->next;
        phead->next=ptemp->next;
        free(ptemp);
    }
    ptemp=NULL;
    return 0;
}

4. 销毁

(1) 函数声明

int destory_list(nd_t **phead);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现
int destory_list(nd_t **phead){
    if(NULL==phead || NULL==*phead){
        printf("传入指针为NULL");
        return -1;
    }
    clean_list(*phead);
    free(*phead);//free参数不能是一个空指针
    *phead=NULL;
    return 0;
}

5. 插入(头插、尾插、任意位置插)

(1)头插
① 函数声明

int insert_list_by_head(nd_t *phead,int num);

② 注意点:
  1. 传入一级指针即可
  2. 需要判断传入的列表指针是否是空指针
③ 示意图

在这里插入图片描述

③ 代码实现
int insert_list_by_head(nd_t *phead,int num){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }

    //创建新节点
    nd_t *ptemp = NULL;
    if(create_node(&ptemp,num)<0)
    {
        printf("内存分配失败\n");
        return -1;
    }
    ptemp->next=phead->next;
    phead->next=ptemp;

    return 0;
}
(2)尾插
① 函数声明

int insert_list_by_tail(nd_t *phead,int num);

② 注意点:
③ 代码实现
int insert_list_by_tail(nd_t *phead,int num){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    nd_t *ptemp=phead;
    //找到尾节点
    while(NULL!=ptemp->next){
        ptemp=ptemp->next;
    }
    //创建新节点
    nd_t *pnew = NULL;
    if(create_node(&pnew,num)<0)
    {
        printf("内存分配失败\n");
        return -1;
    }
    ptemp->next=pnew;
    return 0;
}
(3)任意位置插入
① 函数声明

int insert_list_by_pos(nd_t *phead,int pos,int num);

② 注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
③ 代码实现
int insert_list_by_pos(nd_t *phead,int pos,int num){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(0>pos){
        printf("位置不合理\n");
        return -1;
    }
    nd_t *ptemp=phead;
    //找到要插入的位置的前一个节点
    for(int i=0;i<pos;i++){
        //当ptemp->next为0时,说明不能继续向下遍历了
        if(NULL==ptemp->next){
            printf("位置不合理\n");
            return -1;
        }
        ptemp=ptemp->next;
    }
    
    //创建新节点
    nd_t *pnew = NULL;
    if(create_node(&pnew,num)<0)
    {
        printf("内存分配失败\n");
        return -1;
    }
    pnew->next=ptemp->next;
    ptemp->next=pnew;

    return 0;
}

6. 删除(头删、尾删、任意位置删)

(1)头删
① 函数声明

int insert_list_by_tail(nd_t *phead,int num);

② 注意点:
③ 代码实现
int delete_list_by_head(nd_t *phead){
     if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(NULL==phead->next){
        printf("表为空\n");
        return -1;
    }
    nd_t *ptemp=phead->next;
    phead->next=ptemp->next;
    free(ptemp);
    ptemp=NULL;
    return 0;
}
(2)尾删
① 函数声明

int insert_list_by_tail(nd_t *phead,int num);

② 注意点:
③ 代码实现
int delete_list_by_tail(nd_t *phead){
     if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(NULL==phead->next){
        printf("表为空\n");
        return -1;
    }
    //找到尾节点的前一个节点
    nd_t *ptemp=phead;
    while(NULL!=ptemp->next->next){
        ptemp=ptemp->next;
    }
    free(ptemp->next);
    ptemp->next=NULL;

    return 0;
}
(3)任意位置删除
① 函数声明

int delete_list_by_pos(nd_t *phead,int pos);

② 注意点:
③ 代码实现
int delete_list_by_pos(nd_t *phead,int pos){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(0>pos){
        printf("位置不合理\n");
        return -1;
    }
    nd_t *ptemp=phead;
    //找到要删除的位置的前一个节点
    for(int i=0;i<pos;i++){
        //当ptemp->next为0时,说明此时ptemp位于链表的最后一个节点,但是此时ptemp后的节点是空,不能进行删除操作
        //所以如果ptemp->next->next为空时,就不能继续往后移动了
        if(NULL==ptemp->next->next){
            printf("位置不合理\n");
            return -1;
        }
        ptemp=ptemp->next;
    }
    nd_t *pdel=ptemp->next;
    ptemp->next=pdel->next;
    free(pdel);
    pdel=NULL;
    return 0;
}

7. 修改

(1) 函数声明

int modify_list_by_pos(nd_t *phead,int pos,int num);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现
int modify_list_by_pos(nd_t *phead,int pos,int num){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(0>pos){
        printf("位置不合理\n");
        return -1;
    }
    nd_t *ptemp=phead;
    //找到要修改的位置的节点
    for(int i=0;i<=pos;i++){
        //当ptemp->next为0时,说明此时ptemp位于链表的最后一个节点,不能继续后移了
        if(NULL==ptemp->next){
            printf("位置不合理\n");
            return -1;
        }
        ptemp=ptemp->next;
    }
    ptemp->data=num;
    return 0;
}

8. 查询

(1) 函数声明

int search_list_by_pos(nd_t *phead,int pos,int *num);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现
int search_list_by_pos(nd_t *phead,int pos,int *num){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    if(0>pos){
        printf("位置不合理\n");
        return -1;
    }
    nd_t *ptemp=phead;
    //找到要查找的位置的节点
    for(int i=0;i<=pos;i++){
        //当ptemp->next为0时,说明此时ptemp位于链表的最后一个节点,不能继续后移了
        if(NULL==ptemp->next){
            printf("位置不合理\n");
            return -1;
        }
        ptemp=ptemp->next;
    }
    *num=ptemp->data;
    return 0;
}

9. 链表合并

(1) 函数声明

int merge_list(nd_t *phead1,nd_t **phead2);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现
int merge_list(nd_t *phead1,nd_t **phead2){
    if(NULL==phead1||NULL==phead2||NULL==*phead2){
        printf("传参为空\n");
        return -1;
    }
    //先找到表1的尾部
    nd_t *ptemp=phead1;
    while(NULL!=ptemp->next)
    {
        ptemp=ptemp->next;
    }
    ptemp->next=(*phead2)->next;
    free(*phead2);
    *phead2=NULL;
    return 0;
}

10. 链表排序

(1) 函数声明

int create_node(node_t **list,int *num);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现

11. 链表翻转

(1) 函数声明

int create_node(node_t **list,int *num);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现

12. 链表剔重

(1) 函数声明

int create_node(node_t **list,int *num);

(2)注意点:
  1. 必须传入二级指针
  2. 需要判断传入的列表指针是否是空指针
(3)代码实现

13. 打印链表

(1) 函数声明

int print_list(nd_t *phead);

(2)注意点:
  1. 注意对于边界点的判定
(3)代码实现
//打印
int print_list(nd_t *phead){
    if(NULL==phead){
        printf("传入指针为NULL");
        return -1;
    }
    nd_t *ptemp=phead->next;
    while(NULL!=ptemp){
        printf("%d ",ptemp->data);
        ptemp=ptemp->next;
    }
    putchar(10);
    return 0;
}

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

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

相关文章

STM32_ADC

1、ADC简介 ADC&#xff0c;即Analog-Digital Converter&#xff0c;模拟-数字转换器。 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁。 12位逐次逼近型ADC&#xff0c;1us转换时间。 输入电压范围&#xff1a;0~3.3…

MySQL数据库单表查询中查询条件的写法

1.使用比较运算符作为查询条件 ; !; >; >; <; <; 如上图所示&#xff0c;可以使用命令select 字段&#xff0c;字段 from 表名 where Gender “M”; 即挑选出Gender “M” 的教师&#xff0c; 如上图所示&#xff0c;可以使用命令select 字段&#xff0c;…

fastadmin 树状菜单展开,合并;简要文件管理系统界面设计与实现

一&#xff0c;菜单合并效果图 源文件参考&#xff1a;fastadmin 子级菜单展开合并、分类父级归纳 - FastAdmin问答社区 php服务端&#xff1a; public function _initialize() {parent::_initialize();$this->model new \app\admin\model\auth\Filetype;$this->admin…

chatGPT预训练模型范例之GPT3系列模型的解密

目录 前言 一、GPT的背景 二、GPT的架构 那么如何实现零样本&#xff08;zero-shot&#xff09;学习呢? 这里我们还是主要来看一下 GPT-3 中所谓的 few-/one-/zero- shot 方式分别是什么意思&#xff1f; 三、GPT的应用 四、GPT3的局限性 前言 近年来&#xff0c;预训练…

分割训练日志的可视化

这一部分主要是将mmdetection训练得到的json文件可视化&#xff0c;代码主要源于github&#xff0c;具体哪一个忘记了&#xff08;readme里面没有原址…&#xff09;是专门做的mmdetection 结果可视化的&#xff0c;非常强&#xff01;&#xff01;。使用时如果出现keyerror的话…

MT3041 多项式变换求值

注意点&#xff1a; 1.使用单调栈 2.用ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);避免超时 3.此题除了ans最好不要用long long&#xff0c;如果a[]和b[]都是long long 类型&#xff0c;可能会超内存 4.ans (ans % p p) % p;防止负数 5.使用秦九韶算法计算指数…

MySQL用户管理操作

用户权限管理操作 DCL语句 一.用户管理操作 MySQL软件内部完整的用户格式&#xff1a; 用户名客户端地址 admin1.1.1.1这个用户只能从1.1.1.1的客服端来连接服务器 admin1.1.1.2这个用户只能从1.1.1.2的客服端来连接服务器 rootlocal host这个用户只能从服务器本地进行连…

ptrade从零开始学习量化交易第11期【ptrade策略引擎简介之on_order_response - 委托主推(可选)】

策略引擎简介 更加详细的调用方法&#xff0c;后续会慢慢整理。 也可找寻博主历史文章&#xff0c;搜索关键词使用方案&#xff0c;比如本文涉及函数on_order_response &#xff01; 感谢关注&#xff0c;咨询开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xf…

经验分享:C++ error:‘syscall’ was not declared in this scope

明明已经加了头文件 #include <sys/syscall.h>#define gettid() syscall(__NR_gettid)但是依旧不能使用 syscall() 函数&#xff0c; 检查源码后&#xff1a; sys/syscall.h 内部表示&#xff0c;他封装了 打开对应的 syscall.h 文件内部依旧没有 syscall()函数的声明…

Vue02-黑马程序员学习笔记

一、今日学习目标 1.指令补充 指令修饰符v-bind对样式增强的操作v-model应用于其他表单元素 2.computed计算属性 基础语法计算属性vs方法计算属性的完整写法成绩案例 3.watch侦听器 基础写法完整写法 4.综合案例 &#xff08;演示&#xff09; 渲染 / 删除 / 修改数量 …

炫酷gdb

在VS里面调试很方便对吧&#xff1f;&#xff08;F5直接调试&#xff0c;F10逐过程调试--不进函数&#xff0c;F11逐语句调试--进函数&#xff0c;F9创建断点&#xff09;&#xff0c;那在Linux中怎么调试呢&#xff1f; 我们需要用到一个工具&#xff1a;gdb 我们知道VS中程…

qt中使用tableWidget不显示表头和内容的可能原因

需求是想要把sqlite数据库中的内容通过tableWidget显示出来&#xff0c;但是在使用过程中发现了一些问题 使用ui->tableWidget->setHorizontalHeaderLabels设置表头的时候&#xff0c;发现怎么样都不显示表头&#xff0c;参考这篇文章&#xff0c;应该使用ui->tableW…

Sping6 笔记(一)【优秀的轻量级框架】

Spring6 介绍&#xff1a; 发布时间&#xff1a;2022年11月Spring 框架是一款优秀的轻量级开源框架&#xff0c;为了解决企业应用开发的复杂性而出现Spring 框架的用途&#xff1a;服务器端的开发特点&#xff1a;简单性、可测试性、松耦合性 学习 Spring6 的前置知识&#x…

react组件中的共享数据

在前面的示例中&#xff0c;每个 MyButton 都有自己独立的 count&#xff0c;当每个按钮被点击时&#xff0c;只有被点击按钮的 count 才会发生改变&#xff1a; 然而&#xff0c;你经常需要组件 共享数据并一起更新。 为了使得 MyButton 组件显示相同的 count 并一起更新&…

Socket同步通讯

目录 引言 1. 建立连接 2. 数据传输 3. 同步机制 4. 处理延迟 5. 安全性 6、一对一Socket同步通讯 客户端 代码分析 服务端 代码分析 7、服务端操作 1、首先我们先运行客户端代码 2、服务端点击Connect连接客户端 3、服务端输入信息传输到客户端 4、断开连接 引…

芯片设计公司外协ERP数字化运营:科技与管理的融合

随着信息技术的快速发展&#xff0c;ERP(企业资源计划)系统已经成为现代企业管理不可或缺的一部分。在芯片设计行业&#xff0c;由于产品的复杂性、技术的高要求以及市场的快速变化&#xff0c;外协ERP数字化运营显得尤为重要。 芯片设计公司的外协ERP数字化运营&#xff0c;主…

javaSwing员工工资管理系统(文档+视频+源码)

摘要 由Java swing mysql数据库实现的员工工资管理系统&#xff0c;该项目功能相对完善&#xff0c;有管理员和普通用户两个角色&#xff0c;分别实现了一些列功能&#xff0c;数据库采用的是mysql 系统实现 我们先以员工的身份查询一下&#xff1a; 接下来我们以管理员身份…

Qt | QCalendarWidget 类(日历)

01、QCalendarWidget 类 1、QCalendarWidget 类是 QWidget 的直接子类,该类用于日历,见下图 02、QCalendarWidget 属性 ①、dateEditAcceptDelay:int 访问函数:int dateEditAcceptDelay()const; void setDateEditAcceptDelay(int) 获取和设置日期编辑器的延迟时间(以毫秒…

事务的ACID是什么及扁平化事务、链式事务

一、什么是事务 1.事务&#xff08;Transaction)是区别于数据库文件系统的重要特性之一。事务会把数据库从一种一致状态转换为另一种一致状态。在数据库提交工作时&#xff0c;可以确保要么所有修改都已经保存&#xff0c;要么所有修改都不保存。 2.InnoDB存储引擎中的事物完…

深度学习之基于YoloV5车牌识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与目标 随着智能交通系统的快速发展&#xff0c;车牌识别技术在交通管理、安防监控等领域扮演着越来越…