当前位置: 首页 > news >正文

2.线性表的链式存储-链表

5.1链表的思路理解


顺序表:空间是连续的,先申请再使用
链表:来一个数据申请一块空间

5.2链表的创建


5.2.1结构体理解

typedef int data_t;
typedef struct node {data_t data; //存放一个数据 (普通变量)struct node * next; //存放下一个节点的起始地址 指针的数据类型是指向的这块空
间决定的
}listnode, * linklist;

5.2.2创建函数的实现


5.2.2.1 逻辑分析

前提:头结点不放数据 最后一个元素写成NULL(比较特殊)
1. 申请空间
2. data不需要赋值
3. next = NULL 指针初始化指向NULL 不能随便指 否则可能会变成野指针

5.2.2.2 代码实现

linklist list_create() {linklist H;H = (linklist)malloc(sizeof(listnode));if (H == NULL) { // 注意 此处是两个等号 “ == ”printf("malloc failed\n");return H;}H->data = 0; //可写可不写H->next = NULL;return H;
}

 

5.3链表的头插法


5.3.1 逻辑分析

1、申请空间
2、data赋值
3、连指针(切记防丢)

5.3.2代码实现

int list_tail_insert(linklist H, data_t value) {linklist p;if (H == NULL) {printf("H is NULL\n");return -1;}//1 new node pif ((p = (linklist)malloc(sizeof(listnode))) == NULL) {printf("malloc failed\n");return -1; // 函数的返回类型是int 所以不能返回NULL 应该返回-1}//data赋值p->data = value;//链接指针
p->next = H->next;
H->next = p;return 0;
}

5.4链表的打印


5.4.1 逻辑分析


如何遍历链表?

5.4.2代码实现

int list_show(linklist H) {linklist p;if (H == NULL) {printf("H is NULL\n");return -1;}p = H;while (p->next != NULL) {// 不为空才能打印结点printf("%d ", p->next->data);
//p->data第一个节点是不存放数据的 如果想打印数据 那就得写成p->next->datap = p->next;//p往后移动 直到最后一个数据为NULL 就不去打印了 退出}puts("");return 0;
}

5.5链表的头删法


5.5.1逻辑分析

1. 判断是否为空
2. 保存要删除的节点
3. 链接指针   p = H->next;     H->next = p->next;
4. free要删除的节点

5.5.2代码实现

int list_delete(linklist H) {linklist q;if (H == NULL) { //判断链表存不存在printf("H is NULL\n");return -1;}
if (H->next == NULL) { // 链表是否为空
printf("list is empty\n");
return -1;
}//3 update listq = H->next;  H->next = q->next; //H->next = H->next->next;//4 freeprintf("free:%d\n", q->data); //可以打印一下删除的值free(q);q = NULL;return 0;
}

5.6链表的按位置插入

 

5.6.1逻辑分析

1. 找到插入位置的前一个节点地址 先找位置 a3 因为a4的话你怎么表示a3的地址 (单向链表)
2. 申请空间
3. data赋值
4. 连指针(切记防丢) 先链接后面再前面

5.6.2代码实现

linklist list_get(linklist H, int pos) {linklist p;int i;if (H == NULL) {   //判断表是否存在printf("H is NULL\n");return NULL;}if (pos == -1) { //等于-1 错误 因为下标没有从-1开始数的return H;}if (pos < -1) { // 小于-1 也有问题printf("pos is invalid\n");return NULL;}
// 大于-1 就去找位置p = H;i = -1; //最开始的时候从-1开始  while (i < pos) {p = p->next; // 往后移动一下if (p == NULL) { //当链表比较短的时候 插入的位置比较大的时候 退出printf("pos is invalid\n");return NULL;}i++; //正常情况下 i++ 往后走 找到pos这个位置之后 跳出循环 返回p}return p;
}
int list_insert(linklist H, data_t value, int pos) {linklist p;linklist q;if (H == NULL) { //判断表是否存在printf("H is NULL\n");return -1;}//1 locate node p (pos-1) pos是插入的位置p = list_get(H, pos-1); //找到前一个位置 怎么去获得p呢? 调用list_getif (p == NULL) { //如果等于NULL 说明没有获取成功 否则成功return -1;}//2 new node q 获取成功之后首先去开辟一段空间if ((q = (linklist)malloc(sizeof(listnode))) == NULL) {printf("malloc failed\n");return -1;}q->data = value; //赋值q->next = NULL; //可以省略//3 insertq->next = p->next;p->next = q; // 现在就是连进去了return 0;
}

5.7链表的按位置删除


5.7.1逻辑分析

1. 判断链表是否存在
2. 判断是否为空
3. 找到要删除节点的前一个节点
4. 保存要删除的节点 5. 链接指针   q = p->next;     p->next = q->next;   6. free要删
除的节点

5.7.2代码实现

int list_delete(linklist H, int pos) {linklist p;linklist q;//1if (H == NULL) {printf("H is NULL\n");return -1;}
if (H->next == NULL) {
printf("List is empty\n");
return -1;
}//2 locate priorp = list_get(H, pos-1); // 找到删除结点的位置 pos-1就是前一个结点的位置if (p == NULL) // 位置输入的不合适 就返回return -1;if (p->next == NULL) { // 如果删除的结点是NULL 的时候   就不能删除了printf("delete pos is invalid\n");return -1;}//3 update listq = p->next; // 保存结点的地址p->next = q->next;//p->next = p->next->next;   // 连接指针的那一步//4 freeprintf("free:%d\n", q->data);free(q); // 释放 就是说这个q的地址我不使用了 可以分给别人了 但是q里面的值还存在q = NULL; // 指针指向NULL 就是把值清掉return 0;
}

5.8拓展练习


5.8.1链表的反转

需求:3 ->4 ->5-> 6-> 7     1 头插法   拿个3头插 拿个4 ......循环拿
结果:7 ->6-> 5-> 4-> 3
思路:
1 判断表是否存在
2 判断结点的个数 如果只有一个有效结点 就不需要反转了
3

5.8.1.1逻辑分析

5.8.1.2代码实现

int list_reverse(linklist H) {
//定义两个指针 一个标记剩下的结点 一个指针标记要往下拿拿个结点linklist p;linklist q;if (H == NULL) { //判断链表是否存在printf("H is NULL\n");return -1;}if (H->next == NULL || H->next->next == NULL) { //判断只有一个节点的时候就不需要
反转了return 0;}p = H->next->next; //标记的是剩下的结点H->next->next = NULL; //拿出来的是前两个结点while (p != NULL) {q = p; // q保存一下p 也就是头插的这个节点p = p->next; // 然后往后移动一下 p将后面的结点标记起来  q->next = H->next; // 这个时候直接头插就行了 连接H->next = q; // 连接}return 0;
}

5.8.2 两个有序链表合并


5.8.2.1逻辑分析

5.8.2.2代码实现

linklist list_merge(linklist H1, linklist H2) {linklist p, q;
if (H1 == NULL){
printf("H1 is NULL\n");
return -1;
}
if (H2 == NULL){
printf("H1 is NULL\n");
return -1;
}
p = H1->next;//拿的最小的结点
q = H2->next;
while(p != NULL && q != NULL)
{
if (p->data <= q->data)
{
H1->next = p;
p = p->next;
H1 = H1->next;
}
else
{
H1->next = q;
q = q->next;
H1 = H1->next;
}
}
if(p != NULL)// 判断这个链表的值全部小于L2链表 这样的情况直接去连接
{
H1->next = p;
}
if(q != NULL)
{
H1->next = q;
}
//根据需求释放,如果后面其他函数还用,就不要释放
free(H2);
H2 = NULL;
return r;
}

需求:2 6 3 7 4 9 5
结果:2 3 4 5 6 7 9
思路就是:
依次拿数据 第一个是2 然后拿6 此时去判断两个数大小 再去排序 排好之后拿第三个数;然后再依次比较
表中的数据,在插入到合适的位置,最后保证遍历出来的是有序链表

5.8.3.2代码实现

int list_order(linklist H){
linklist p,q,r;// 一个标记拿出来的结点 一个存放剩余的结点 r始终从头开始遍历一遍
int t;
if(H == NULL){
printf("H is NULL");
return -1;
}
p = H->next;
H->next = NULL;
while(p != NULL)
{
q = p;
p = p->next;
r = H;//代表指向结点的开始
while(r->next && r->next->data < q->data){
r = r->next;
}
q->next = r->next; //插入结点
r->next = q;
}
return 0;
}

 

 

相关文章:

  • 掌握产品功能结构图,优化项目开发流程
  • 精粹汇总:大厂编程规范(持续更新)
  • 面向GPU、CPU及机器学习加速器的机器学习编译器
  • 如何关闭WordPress中的评论通知
  • 并发编程-Synchronized
  • WinUI:使用DataGrid控件显示表格
  • 打印机共享问题一键解决,附带设置维护工具
  • 会计-收入-3-关于特定交易的会计处理
  • Power Query动态追加查询(对文件夹下文件汇总)
  • SSM框架实现学生管理系统的需求分析与设计详解
  • 安科瑞亮相2025 SNEC国际太阳能光伏与智慧能源展
  • Mac电脑通过 IntelliJ IDEA 远程连接 MySQL 的详细教程
  • 一个模板元编程示例
  • 亚马逊Woot秒杀:引爆销量
  • Day 48
  • c++动态规划4——环形动态规划
  • 岛屿周长问题的三种解法:直接计数法、数学计算法与深度优先搜索
  • redis-7.4.4使用
  • 论索引影响性能的一面④ 索引失踪之谜【上】
  • 学习日记-day29-6.13
  • wordpress响应式cms/惠州seo收费
  • 酒类招商网站大全/苏州seo关键词优化方法
  • 专业网站建设报价/全案网络推广公司
  • 做视频网站赚做视频网站赚/东莞网站seo公司
  • 昆山营销型网站建设/手机优化软件下载
  • 自适应网站一般用什么框架做/百度sem竞价推广