文章目录

  • 第一节:单链表删除操作
  • 第二节:考研真题
    • 1. 解题设计
    • 2. 代码实现
    • 3. 时间复杂度分析

第一节:单链表删除操作

删除操作流程图:

通过流程图,我们写出代码:

#include <stdio.h>
#include <stdlib.h>typedef int ElemType;
typedef struct LNode{ElemType data;struct LNode* next;
}LNode,*Linklist;// 尾插法新建链表
Linklist list_tail_insert(Linklist &L){int x;L= (Linklist)malloc(sizeof(LNode)); // 带头结点的链表LNode *s,*r=L; // 写成LinkList s,r=L;也可以。r代表链表表尾结点,指向链表尾部scanf("%d",&x);while (x!=9999){s= (LNode*)malloc(sizeof(LNode));s->data=x;r->next=s;  // 让r指针指向新的尾部r=s; // 让r本身指向新的尾部scanf("%d",&x);}r->next=NULL; // 尾结点的next指针赋值为NULLreturn L;
}// 按序号查找结点值
Linklist GetElem(Linklist L,int i){int j=0;if(i<0){return NULL;}while (L && j<i){L=L->next;j++;}return L;
}// 删除某个位置元素
bool ListDelete(Linklist L,ElemType i){Linklist p=GetElem(L,i-1);if(NULL==p){return false;}Linklist q;  // 用来存储要删除的节点地址q=p->next;p->next=q->next; // 断链free(q); // 释放空间return true;
}// 打印链表中每个结点的值
void print_list(Linklist L){L=L->next; // 头结点指向第一个指针while (L!=NULL){printf("%3d",L->data);L=L->next; // 指向下一个指针}printf("\n");
}int main() {Linklist L,search;  // L仅表示链表头,是结构体指针类型list_tail_insert(L);print_list(L); // 打印链表ListDelete(L,4);  // 删除第4个位置元素print_list(L);return 0;
}
F:\Computer\Project\practice\12\12.1-head-insert\cmake-build-debug\11_1_head_insert.exe
1 2 3 4 5 99991  2  3  4  51  2  3  5进程已结束,退出代码为 0

对于删除元素的逻辑,可以用一张图来表示:

分析

  1. 头指针的数据域始终为空,位置不动。
  2. 删除第i个元素实际上是将原本i元素的next赋值给i-1个位置元素的next。也叫作断链。这样第i-1个元素就和第i+1个元素链接起来,形成链表。
  3. 将要删除的元素地址保存起来,并做释放空间处理。

第二节:考研真题

解读

  1. 空间复杂度为O(1),即不能额外申请空间。
  2. 找到链表的中间结点,前面一半是链表L,将链表的后半部分给一个新的头结点L2,然后将链表L2原地逆置。
  3. 将L和逆置后的L2链表按照L’进行合并。

1. 解题设计

第一阶段:如何找到链表的中间结点

定义两个指针pcur和ppre,让pcur指针每次走两步,ppre指针每次走一步,这样当pcur指针走到最后,那么ppre指针刚好在中间。指针p每次循环走两步,因此每一步都要注意判断是否为NULL。

第二阶段:后一半链表设置为了L2,如何让L2原地逆置

首先我们要判断链表是否为空,如果为空,就返回。如果只有一个结点,也不需要逆置,直接返回。

  1. 链表原地逆置,我们需要使用3个指针,分别为r,s,t,他们分别指向链表的1,2,3的位置,也就是前3个结点。
  2. 让s->next=r,这样2号结点就指向了1号结点,完成了逆置。
  3. 这是,r=s,s=t,t=t->next,通过这个操作,r,s,t分别指向了链表的2,3,4位置结点。在循环执行第2步。当t为NULL时,结束循环。
  4. 循环结束时,t为NULL,这是s是最后一个结点,r是倒数第二个结点,需要再执行一次s->next=r。
  5. 最后需要L2->next->next=NULL;因为原有链表的头结点变成了链表的最后一个结点,最后一个结点的next需要为NULL,这时让L2指向s,因为s是原链表最后一个结点,完成逆置后,就是第一个节点,因此链表头结点L2指向s。

第三阶段:将L和L2链表合并,合并时轮流放入一个结点

我们依然需要3个指针,pcur,p,q,让pcur始终指向新链表尾部,初始化为pcur=L->next。使用p指针始终指向链表L待放入的节点,初始化为p=L->next(因为L的第一个结点就是新链表的第一个结点)。q始终指向L2待放入的节点,初始化为q=L2->next。

开启循环,while(NULL!=p&&NULL!=q),首先将pcur->next=q,然后q=q->next和pcur=pcur->next,接着pcur->next=p,然后p=p->next和pcur=pcur->next。直到循环结束。循环结束后,有可能L还剩余一个结点,也可能L2还剩余一个结点,但是只会有一个剩余的节点。判断p不为NULL,把p放入,如果q不为NULL,把q放入即可。

2. 代码实现

#include <stdio.h>
#include <stdlib.h>typedef int ElemType;
typedef struct LNode{ElemType data;struct LNode* next;
}LNode,*Linklist;// 尾插法新建链表
Linklist list_tail_insert(Linklist &L){int x;L= (Linklist)malloc(sizeof(LNode)); // 带头结点的链表LNode *s,*r=L; // 写成LinkList s,r=L;也可以。r代表链表表尾结点,指向链表尾部scanf("%d",&x);while (x!=9999){s= (LNode*)malloc(sizeof(LNode));s->data=x;r->next=s;  // 让r指针指向新的尾部r=s; // 让r本身指向新的尾部scanf("%d",&x);}r->next=NULL; // 尾结点的next指针赋值为NULLreturn L;
}// 寻找中间结点并返回第二个链表
void find_middle(Linklist L,Linklist &L2){L2=(Linklist) malloc(sizeof(LNode));Linklist pcur,ppre;pcur=ppre=L->next;  // 初始化双指针均为L的第一个结点while (pcur!=NULL){pcur=pcur->next;  // pcur走第一步if(NULL==pcur){break;}pcur=pcur->next;  // pcur走第二步if(NULL==pcur){break;}ppre=ppre->next;  // ppre走一步}L2->next=ppre->next;ppre->next=NULL;
}// 原地逆转L2
void reverse(Linklist &L2){Linklist r,s,t;r=s=t=L2->next;if(NULL==r){ // 链表为空return;}s=t=t->next;if(NULL==t){  // 链表只有一个结点return;}t=t->next;while (NULL!=t){s->next=r;r=s;  // 三个节点依次向后移动s=t;t=t->next;}s->next=r;L2->next->next=NULL;  // 链表的第一个结点的next要为NULLL2->next=s;  // s是头部
}// 合并链表
void merge(Linklist L,Linklist L2){Linklist pcur,p,q;pcur=p=L->next;q=L2->next;p=p->next;while (q!=NULL && p!=NULL){pcur->next=q; // 链表上给过来一个结点q=q->next; // q往后走一步,q在L2上pcur=pcur->next; // 新链表往后走一个pcur->next=p;   // 链表L2上给过来一个结点p=p->next; // q往后走一步,它在L上pcur=pcur->next; // 新链表往后走一步}if(NULL!=q){pcur->next=q;}if(NULL!=p){pcur->next=p;}
}// 打印链表中每个结点的值
void print_list(Linklist L){L=L->next; // 头结点指向第一个指针while (L!=NULL){printf("%3d",L->data);L=L->next; // 指向下一个指针}printf("\n");
}int main() {Linklist L,search;  // L仅表示链表头,是结构体指针类型list_tail_insert(L);  // 尾插法新建列表print_list(L); // 打印链表Linklist L2=NULL; // 寻找中间结点并返回第二个链表find_middle(L,L2);printf("---------------------\n");print_list(L);print_list(L2);printf("---------------------\n");reverse(L2);   // L2原地逆置print_list(L2);printf("---------------------\n");merge(L,L2);  // 重新合并链表free(L2);print_list(L);return 0;
}
F:\Computer\Project\practice\12\12.2-head-insert\cmake-build-debug\11_1_head_insert.exe
1 2 3 4 5 6 7 8 9 99991  2  3  4  5  6  7  8  9
---------------------1  2  3  4  56  7  8  9
---------------------9  8  7  6
---------------------1  9  2  8  3  7  4  6  5进程已结束,退出代码为 0

3. 时间复杂度分析

find_middle函数有一个while循环,因为pcur每次移动两个结点,因为循环次数为n/2,忽略首项系数,时间复杂度为O(n)。

reverse函数值遍历了L2链表,遍历长度为n/2,所以时间复杂度为O(n)。

merge函数循环遍历次数也是n/2,因此时间复杂度为O(n)。

三个函数总的运行次数为1.5n,忽略首项系数,因此时间复杂度为O(n)。

【408篇】C语言笔记-第十二章(单链表的删除考研真题实战)相关推荐

  1. R语言实战笔记--第十二章 重抽样(置换检验)与自助法

    R语言实战笔记–第十二章 重抽样(置换检验)与自助法 标签(空格分隔): R语言 重抽样 自助法 置换检验 置换检验 双样本均值检验的时候,假设检验的方法就是,检查正态性.独立性.方差齐性,分别对应的 ...

  2. 谭浩强c语言不讲位运算呢,谭浩强C语言教程第十二章-位运算.doc

    谭浩强C语言教程第十二章-位运算 12位运算1 12.1位运算符C语言提供了六种位运算符:1 12.1.1按位与运算1 12.1.2按位或运算2 12.1.3按位异或运算2 12.1.4求反运算3 1 ...

  3. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  4. c语言压缩文本文件北京理工大学,北京理工大学C语言程序设计第十二章文件.ppt...

    北京理工大学C语言程序设计第十二章文件 2000年1月25日 北京理工大学 / 第十二章 文件 第一节 文件概述 第二节 文件的处理 第三节 文件的顺序读写操作 第四节 文件的随机读写操作 第五节 文 ...

  5. Linux(b站视频兄弟连)自学笔记第十二章——Linux服务管理

    Linux(b站视频兄弟连)自学笔记第十二章--Linux服务管理 服务分类 RPM包安装服务的管理 独立服务的管理 基于xinetd 的服务管理 源码包服务管理 服务分类 RPM包安装服务的管理 独 ...

  6. 高级shell编程笔记(第十二章 外部过滤器,程序和命令)

    第十二章 外部过滤器,程序和命令 标准的UNIX命令使得脚本更加灵活.通过简单的编程结构把shell指令和系统命令结合起来,这才是脚本能力的所在. 12.1 基本命令 新手必须掌握的初级命令 ls 基 ...

  7. python 宝典 笔记 第十二章 存储数据和对象 (各种对象转换成字符串)

    第十二章 存储数据和对象 12.1数据存储概述 12.1.1文本与二进制对比 文本格式易于阅读和调试,跨平台性能好.二进制格式占用空间小,适于按记录存取. 12.1.2压缩 假如对象的大小开始成为问题 ...

  8. Android群英传读书笔记——第十二章:Android 5.X新特性详解

    第十二章目录 12.1 Android5.X UI设计初步 12.1.1 材料的形态模拟 12.1.2 更加真实的动画 12.1.3 大色块的使用 12.2 Material Design主题 12. ...

  9. css层叠样式表基础学习笔记--第十二章 我要自学网首页实战

    第十二章 我要自学网首页实战 12-01 页面分析 12-02 工作准备 12-03 搜索区块页面结构 12-04 导航条布局 12-05 幻灯片布局 12-06 公告栏布局 12-07 远程培训班布 ...

最新文章

  1. 面试时写不出排序算法?看这篇就够了
  2. Keras,亡于谷歌?
  3. BZOJ 1590.Secret Message 秘密信息(Trie树) [Usaco2008 Dec]【BZOJ计划】
  4. mysql查询当前use的数据库
  5. 相关子查询 与非相关子查询
  6. 安装brew提示/usr/local/bin is not in your PATH.
  7. 读书笔记2014年第1本:《赤裸裸的统计学》
  8. flask中的请求上下文
  9. java 国家名称排序,我有一个国家名单。我想按字母顺序对它进行排序,除了两个我想放在第一位的国家...
  10. linux 执行iso 文件,linux可以加载iso镜像文件到启动项吗
  11. [置顶] 根据 子网掩码 算出 最大主机数目
  12. 反装逼指南:掀起机器学习的神秘面纱
  13. 自学python买什么教材-学习Python的正确姿势—基础教学,教科书该怎么买?
  14. mysql connector c++与 visual studio 2012 联合使用
  15. 年度回顾 | 2019 年的 Apache Flink(文末有福利)
  16. 虚拟服务器数据库怎么导入数据库,BlueHost虚拟主机使用SSH怎么导入MySQL数据库...
  17. python文本挖掘教程,4个步骤教你轻松完成文本挖掘预处理(附python代码)
  18. Visual Studio Ultimate 2013(VS2013旗舰版 下载地址及哈希校验)
  19. React 之 Expected an assignment or function call and instead saw an expression 解决办法
  20. Excel表格导入数据库进行判断是否有相同的数据

热门文章

  1. css的box模型_拆箱CSS Box模型的基础
  2. FL水果21最新版本电脑编曲软件FL Studio更新
  3. 计算机英语名词简释.doc
  4. 物联网卡让物流行业“灵活”起来
  5. Wordpress 网站设计 文件管理器插件
  6. html+css制作豆瓣读书页面
  7. 项目总结(关于fixed/absolute固定的底部按钮被input输入框的键盘顶上去的问题一般安卓手机会出现这种问题)
  8. [Linux] VMware虚拟机开机后直接进入memtest
  9. 孙正义:30年后AI的智商将达到10000,你与机器人之间的智力将差49个半爱恩斯坦
  10. 关于计算机应用的板报,“计算机应用基础”电子板报制作教学设计