单向链表与双向循环链表
文章目录
- 单链表操作
- 大纲
- 核心⭐
- 1-链表的建立
- 1.1head,tail,p相关问题
- 2-链表的打印
- 3-链表的插入
- 3.1 尾插法
- 3.1.1一级指针无法对空链表进行尾插问题
- 3.2 头插法
- 3.3 单项链表的节点后插入
- 4-链表的删除
- 4.1 尾删法
- 4.2 头删法
- 4.3 单向节点的后删除
- 5-链表的查找
- 5.1查找兼具修改功效
- 6-链表的反转
- 6.1 三指针遍历
- 6.2 新链表头插法
- C解法
- 双向链表
- 双向循环链表
- 初始化,创建新链表
- 打印
- 头插与尾插
- 头删与尾删
- 插入
- 删除
- 链表的销毁
- 链表的销毁
单链表操作
大纲
链表形式 |
---|
单项,双向 |
带头(头节点不存有效数据),不带头 |
循环,不循环 |
组合起来有:2x2X2=8种组合方式
核心⭐
- TIPS:通过指针的修改,都是通过形参和实参同时指向一块区域,通过形参简介修改实参,而对于形参本身的赋值,删除无法影响到实参本身;若要修改实参本身,只能通过二级指针的方式;
- 如果有可能第一个节点会发生改变,那就要传二级指针(带头节点可以不传)
1-链表的建立
#include<stdio.h>
#include<stdlib.h>
typedef struct _list {int num;struct _list* next;
}list;
list* build();
int main() {list* head;head = build();Print_Stu_Doc(head);system("pause");return 0;
}
struct _list* build() {int val;list* head, * tail;head = tail = NULL;scanf("%d", &val);if (-1 == val) {return head;}while (-1 != val) {list* p = (list*)malloc(sizeof(list));p->num = val;p->next = NULL;if (NULL == head) {head = p;}else tail->next = p;tail = p;scanf("%d", &val);}return head;
}
1.1head,tail,p相关问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9P5ui1D-1664027324418)(C:\Users\Hello3\AppData\Roaming\Typora\typora-user-images\image-20220418222220080.png)]
head,tail,p属于三个不同的地址,即便三者指向同一区域,三者互不影响;
head=tail=NULL;
head=p;
tail=p
p->num = val;p->next = NULL;if (NULL == head) {head = p;}else tail->next = p;tail = p;scanf("%d", &val);
由于tail和head同时指向同一个指针域;tail->next所修改的是tail和head同时指向的指针域,也会影响到head->next;
在这里,第一步赋值时候;
head=p;
tail=p
在这里由于head和tail不是同一指针,所以对tail=p;进行修改不会影响到head;
2-链表的打印
void list_print(list* head);
void list_print(list* head) {list * ptr;if (head == NULL) {printf("No Records\n");return;}for (ptr = head; ptr; ptr = ptr->next)printf("%d ", ptr->num);printf("\n");
}
3-链表的插入
3.1 尾插法
要改变头指针,传二级指针,不改变头指针,传一级指针
int main() {...........list_pushback(&head, 5);.......
}
void list_pushback(list** pplist, int val);
void list_pushback(list** pplist, int val) {list* newnode = newchain(val);if (NULL == *pplist) {//判断是否为空指针*pplist = newnode;}else {list* tail = *pplist;while (tail->next) {//定位到尾tail = tail->next;}tail->next = newnode;}
}
函数:值的传递,并对值进行操作:
一级指针的值:所指向的数据
二级指针的值:所指向的二级指针
3.1.1一级指针无法对空链表进行尾插问题
(实则是函数实参形参问题)
void list_pushback(list* plist, int val) {list* newnode = newchain(val);if (NULL == plist) {plist = newnode;}else {list* tail = plist;while (tail->next) {//定位到尾tail = tail->next;}tail->next = newnode;}
}
如果使用一级指针,那么当传入的plist为空的时候,对形参plist的修改无法影响到实参,故无法成功尾插;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8XOe13U-1664027324419)(C:\Users\Hello3\AppData\Roaming\Typora\typora-user-images\image-20220422135115410.png)]
//当为非空指针的时候,是通过tail指向和实参plist一样的区域,在对tail->next赋值的同时修改了实参plist->next指向区域的值!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAiBbDh9-1664027324419)(C:\Users\Hello3\AppData\Roaming\Typora\typora-user-images\image-20220419170140478.png)]
当head是空时,我们要让实参head被赋值(newcode),是修改head本身
当head不是空时,我们修改的他next指向的值,是修改head里的指针
3.2 头插法
void list_pushfront(list** pplist, int val)void list_pushfront(list** pplist, int val) {list* newcode = newchain(val);newcode->next = *pplist;*pplist = newcode;
}
头插法即便头指针是空,也能照场头插;
//newcode->next=*pplist(NULL)
3.3 单项链表的节点后插入
void list_insertafter(list* node, int x);
//链表节点后插入 (对于单项链表,节点前前插需要传头地址,效率低麻烦,多不使用)
void list_insertafter(list* node, int x) {assert(node);//断言,防止node是空 <assert.h>list *next =newchain(x);next->next = node->next;node->next = next;
}
4-链表的删除
4.1 尾删法
void list_popback(list**pplist);void list_popback(list**pplist) {if ( *pplist== NULL)return;else if ((*pplist)->next == NULL) {free(*pplist);*pplist = NULL;}else {list* pre = NULL;list* tail = *pplist;while (tail->next) {pre = tail;tail = tail->next;}free(tail);//动态删除空间tail = NULL;pre->next = NULL;}
}
一级指针无法处理没有节点,或者只有一个节点的情况;
只有一个节点时,不存在pre,故无法通过pre使plist指向NULL;
//形参本身=NULL的修改无法影响到实参
4.2 头删法
void list_popfront(list** pplist);
void list_popfront(list** pplist) {if (*pplist == NULL) {return;}else {list* next = (*pplist)->next;//保存头节点的下一个地址;free(*pplist); //便于free掉内存*pplist = next; //也可以解决*pplist只有一个节点的问题(直接等于*pplist->next(NULL))}
}
4.3 单向节点的后删除
void list_popafter(list* node);
//链表节点后删 (对于单项链表,节点前前删需要传头地址,效率低麻烦,多不使用)
void list_popafter(list* node) {list* next = node->next;if (next) {node->next = next->next;free(next);next = NULL;}
}
5-链表的查找
list* list_find(list* head, int x);
list* list_find(list* head, int x) {list* cur = head;while (cur) {if (x == cur->num)return cur;cur = cur->next;}return NULL;
}
5.1查找兼具修改功效
代码如下
单向链表与双向循环链表相关推荐
- 顺序表、链表、双向循环链表
顺序表.链表.双向循环链表 SeqList.h #pragma once #include<stdio.h>#define ListSize 100 //线性表的最大长度 typedef ...
- 【数据结构】单链表和双向循环链表
文章目录 单链表 链表的概念及结构 链表的分类 链表的实现 动态申请一个节点 创建链表 单链表打印 单链表尾插 单链表尾删 单链表头插 单链表头删 单链表的查找 单链表在pos位置之后插入x 单链表删 ...
- 【链表】双向循环链表的实现
前言 链表是一种物理存储结构上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的链表的结构总共有8种,我们这里来进行带头双向循环链表的增删查改实现 双向循环链表的优势是什么? ...
- 双向循环链表的讲解及实现(图解+代码/C语言)
本次为大家分享的是双向循环链表的增删查改等系列操作. 目录 一.图解双向循环链表结构 二.分步实现 (1)创建并初始化 (2)链表元素打印 (3)头插和尾插 (4)判断链表为空 (5)头删和尾删 (6 ...
- 单向循环链表改成双向循环链表
#include<stdio.h> #include<stdlib.h> typedef char Elemtype; int length = 8; char s[8] = ...
- 双向循环链表 (C语言实现双向循环链表) ------- 算法笔记003
概念 我们常说的单链表是有向的链表,因为链表1中有next指针它对应指向链表2的地址 而链表2无法指向链表1,所以我们说它是单向的链表. 而双向链表则是链表1可以访问到链表2,链表2也可以访问到链表1 ...
- 数据结构篇 --- 带头双向循环链表增删查改
简述:有了前篇单链表的增删查改的基础 也是出于带头双向循环链表本身的优势 双链表的增删就变得格外简单.让我们一起来体验一下. 目录 带头双向循环链表图解: 带头双向循环链表基本结构: 带头双向循环链 ...
- 一文搞定带头双向循环链表
什么是链表 链表的种类 最经典的两种链表 带头双向循环链表详细 什么是链表 在数据结构线性表里 除了顺序表 还有一种我们不得不说 他就是链表 链表的关键就是指针 创建出一块节点空间存储着 一边是val ...
- 数据结构——带头结点双向循环链表
相比较与单链表,双向循环链表每个结点多了一个prev指针域,用于指向该结点的前驱,并且链表的头尾结点也用指针域相连.所以对于带头结点的双向循环链表的判空条件为head->next=head;除此 ...
最新文章
- 区分真实模式的两个标准
- 第五章 文件和目录管理
- 【STM32-V7】STM32H743XIH6开发板,丰富软件资源,强劲硬件配置,大量软件解决方案持续更新中(2020-07-22)
- xhtml中的五个块元素
- 打印纸张尺寸换算_纸张尺寸与开(K)数换算
- c语言中格式化字符串系列函数包括,解析C语言中常用的格式化输入、输出函数...
- 使用TensorFlow.js的AI聊天机器人六:生成莎士比亚独白
- java语言jdk_Java语言环境(JDK的安装教学)
- 研究生期间如何成为科研大佬?
- 证明您履历表经验的防弹五步法
- Spring Cloud Gateway初体验
- 如何减小电压跟随器输出电阻_电压跟随器只会跟踪?不!请看看它对电路的“魔力”。...
- 微信公众号文章怎么制作?
- linux修改ip配置文件路径,Linux系统更改IP地址及连接XShell5
- C/C++笔试题(很多)
- linux注销系统有几种方法,怎么注销Linux子系统
- 1.5. 唤醒任务:TTWU(try_to_wake_up)
- 英语四级常考100个短语
- 五、MUX-VLAN QinQ技术
- 系统盘制作并详细记录从零重装win10系统