C语言链表专题复习
- 格式:doc
- 大小:80.00 KB
- 文档页数:10
c语言超时重发机制的链表C语言超时重发机制的链表引言:在网络通信中,超时重发机制是一种常见的应对网络延迟和丢包的技术手段。
本文将介绍如何使用C语言实现一个超时重发机制的链表,以及其原理和应用。
一、超时重发机制的链表超时重发机制的链表是一种数据结构,用于管理需要进行超时重发的数据包。
它的主要特点是可以按照发送顺序进行管理,并且能够自动检测超时并进行重发操作。
二、链表的基本结构链表是由一系列节点组成的数据结构,每个节点包含一个数据域和一个指针域。
在超时重发机制的链表中,每个节点代表一个数据包,并且需要额外包含超时时间和重发次数等信息。
三、链表的初始化在使用链表之前,需要进行初始化操作。
初始化操作主要包括创建链表头节点,并将头节点的指针域置空。
四、数据包的插入在发送数据包时,将数据包插入到链表的末尾。
这需要遍历链表,找到最后一个节点,并将其指针域指向新节点。
五、超时检测与重发超时检测是链表中的重要操作,用于判断是否有数据包超时。
当一个数据包超时时,需要将其重新发送,并更新超时时间和重发次数等信息。
六、数据包的删除当一个数据包发送成功后,需要从链表中删除。
删除操作需要遍历链表,找到对应的节点,并更新前后节点的指针域。
七、链表的销毁当所有数据包都发送完成或不再需要重发时,需要销毁链表。
销毁链表操作主要包括释放所有节点的内存空间,并将链表头节点的指针域置空。
八、超时重发机制的应用超时重发机制在网络通信中广泛应用于保证数据可靠性和提高传输效率。
例如,在TCP协议中,超时重发机制被用于保证数据包的可靠传输。
九、注意事项在实现超时重发机制的链表时,需要注意以下事项:1. 设置合理的超时时间,以适应不同的网络环境。
2. 避免重复发送已经成功发送的数据包,以节省网络带宽和资源。
3. 考虑异常情况,如网络中断或故障,需要对链表进行适当的处理。
结论:超时重发机制的链表是一种实现超时重发的重要数据结构。
它可以有效地应对网络延迟和丢包等问题,提高数据传输的可靠性和效率。
c语言链表操作题C语言链表操作题一、问题描述假设有一个链表,每一个节点都包含一个整数,节点的结构体定义如下:```struct ListNode {int val;struct ListNode *next;};```请你完成以下链表操作函数:1. `struct ListNode* createList(int *arr, int size)`:传入一个整数数组和数组的长度,返回一个链表的头节点,链表的节点顺序和数组顺序一致。
2. `void displayList(struct ListNode *head)`:传入链表的头节点,打印链表中所有的节点值,用空格隔开,最后换行。
3. `int lengthOfList(struct ListNode *head)`:传入链表头节点,返回链表的长度。
4. `void insertNode(struct ListNode *head, int index, int val)`:传入链表的头节点、插入的位置和插入的值,在指定位置插入一个新节点。
5. `void deleteNode(struct ListNode *head, int index)`:传入链表的头节点和删除的位置,删除指定位置的节点。
6. `void reverseList(struct ListNode *head)`:传入链表的头节点,翻转整个链表。
7. `int findValInList(struct ListNode *head, int val)`:传入链表的头节点和要查找的值,返回第一个匹配的节点的下标,如果没有匹配的,则返回-1。
二、解题思路1. 创建链表:根据数组中元素的数量,循环遍历数组,每结构体当做链表节点,并记录对应下一个节点,最后返回链表头节点。
2. 打印链表:循环遍历链表的每一个节点,打印节点的val,并在每个节点之间添加空格,最后在尾部添加换行符。
3. 计算链表长度:从链表头节点开始循环遍历每一个节点,直到当前节点的next指针指向NULL,每遍历到一个节点就计数器加1。
链表c语言经典例题
链表是计算机科学中的经典数据结构之一,常用于存储和操作动态数据。
以下是一些常见的链表例题,可以帮助理解链表的基本操作和应用。
1. 链表的创建:
- 创建一个空链表。
- 创建一个包含指定节点值的链表。
2. 链表的插入操作:
- 在链表的头部插入一个节点。
- 在链表的尾部插入一个节点。
- 在指定位置插入一个节点。
3. 链表的删除操作:
- 删除链表的头节点。
- 删除链表的尾节点。
- 删除指定数值的节点。
4. 链表的查找操作:
- 查找链表中指定数值的节点。
- 查找链表的中间节点。
5. 链表的逆序操作:
- 反转整个链表。
- 反转链表的前 N 个节点。
- 反转链表的一部分区间内的节点。
6. 链表的合并操作:
- 合并两个有序链表,使其有序。
- 合并 K 个有序链表,使其有序。
7. 链表的环检测:
- 判断链表中是否存在环,若存在,则返回环的起始节点。
8. 链表的拆分操作:
- 将一个链表按照奇偶位置拆分成两个链表。
以上是一些链表的经典例题,通过解答这些例题,可以加深对链表结构和基本操作的理解。
在编写对应的 C 语言代码时,需要注意链表节点的定义、指针的使用以及内存的动态分配和释放等问题。
计算机等级考试二级C语言程序设计专项训练题——单链表一.程序填空题1.给定程序的主函数中,已给出由结构体构成的链表结点a、b、c,各结点的数据域中均存入字符,函数fun的功能是:将a、b、c 三个结点链接成一个单向链表,并输出链表结点中的数据。
请在下划线处填入正确的内容并将下划线删除,使程序得出正确的结果。
注意:不得增行或删行,也不得更改程序的结构!#include <stdio.h>typedef struct list{char data;struct list *next;}Q;void fun(Q *pa, Q *pb, Q *pc){Q *p;/**********found**********/pa->next=___1___;pb->next=pc;p=pa;while( p ){/**********found**********/printf(" %c",____2_____);/**********found**********/p=____3____;}printf("\n");}int main(){Q a, b, c;a.data='E';b.data='F';c.data='G'; c.next=NULL;fun( &a, &b, &c );return 0;}2.给定程序中,函数fun的功能是:统计出带有头结点的单向链表中结点的个数,存放在形参n所指的存储单元中。
请在下划线处填入正确的内容并将下划线删除,使程序得出正确的结果。
注意:不得增行或删行,也不得更改程序的结构!#include <stdio.h>#include <stdlib.h>#define N 8typedef struct list{int data;struct list *next;} SLIST;SLIST *creatlist(int *a);void outlist(SLIST *);void fun( SLIST *h, int *n){SLIST *p;/**********found**********/___1___=0;p=h->next;while(p){(*n)++;/**********found**********/p=p->___2___;}}int main(){SLIST *head;int a[N]={12,87,45,32,91,16,20,48}, num;head=creatlist(a);outlist(head);/**********found**********/fun(___3___, &num);printf("\nnumber=%d\n",num);return 0;}SLIST *creatlist(int a[]){SLIST *h,*p,*q;int i;h=p=(SLIST *)malloc(sizeof(SLIST));for(i=0; i<N; i++){q=(SLIST *)malloc(sizeof(SLIST));q->data=a[i]; p->next=q; p=q;}p->next=0;return h;}void outlist(SLIST *h){SLIST *p;p=h->next;if (p==NULL) printf("The list is NULL!\n");else{printf("\nHead ");do{printf("->%d",p->data);p=p->next;} while(p!=NULL);printf("->End\n");}}3.给定程序中,函数fun的功能是:计算出带头结点的单向链表中各结点数据域之和作为函数值返回。
c语言链表复习题C语言链表复习题链表是C语言中常用的数据结构之一,它可以用来存储和操作大量的数据。
在这篇文章中,我们将复习一些与链表相关的题目,以加深对链表的理解和运用。
1. 链表的基本结构链表由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。
我们可以通过定义一个结构体来表示链表节点,例如:```cstruct Node {int data;struct Node* next;};```2. 创建一个链表首先,我们需要定义一个指向链表头节点的指针。
然后,我们可以通过动态分配内存来创建一个新节点,并将头指针指向该节点。
接下来,我们可以按照需要添加更多的节点。
例如,下面的代码演示了如何创建一个包含三个节点的链表:```cstruct Node* head = NULL;// 创建第一个节点struct Node* node1 = (struct Node*)malloc(sizeof(struct Node));node1->data = 1;node1->next = NULL;head = node1;// 创建第二个节点struct Node* node2 = (struct Node*)malloc(sizeof(struct Node));node2->data = 2;node2->next = NULL;node1->next = node2;// 创建第三个节点struct Node* node3 = (struct Node*)malloc(sizeof(struct Node));node3->data = 3;node3->next = NULL;node2->next = node3;```3. 遍历链表要遍历链表,我们可以使用一个指针从头节点开始,依次访问每个节点的数据元素。
下面的代码演示了如何遍历上述创建的链表,并打印每个节点的数据:```cstruct Node* current = head;while (current != NULL) {printf("%d ", current->data);current = current->next;}```4. 插入节点要在链表中插入一个新节点,我们首先需要找到要插入位置的前一个节点。
c++数据结构链表的选择题
摘要:
1.链表的定义与特点
2.链表的种类
3.链表的优缺点
4.选择题解答
正文:
一、链表的定义与特点
链表是一种数据结构,它是由一系列节点组成,每个节点包含两个部分:数据部分和指针部分。
数据部分用于存储数据,指针部分用于指向下一个节点。
链表的第一个节点称为头节点,最后一个节点称为尾节点。
链表的特点是每个节点之间通过指针进行连接,而且每个节点都可以随时删除或插入。
二、链表的种类
链表主要有两种类型:单链表和双链表。
单链表只有一个指针域,它只能指向下一个节点;双链表有两个指针域,一个指向前一个节点,一个指向后一个节点。
双链表在插入和删除操作时比单链表更加方便。
三、链表的优缺点
链表的优点是插入和删除操作比较灵活,不需要移动元素,时间复杂度为O(1)。
链表的缺点是存储空间利用率较低,每个节点需要额外的指针空间。
另外,链表的访问速度较慢,因为需要遍历整个链表才能找到目标节点。
下面哪种选项描述了链表的特点?A) 可以随机访问元素B) 拥有固定大小的内存空间C) 元素之间通过指针连接D) 可以自动调整大小答案: C在链表中,头节点的作用是什么?A) 存储链表的长度B) 存储链表的最后一个节点C) 存储链表的第一个节点D) 存储链表的中间节点答案: C下面哪种选项描述了双向链表的特点?A) 每个节点只有一个指针指向下一个节点B) 每个节点只有一个指针指向上一个节点C) 每个节点同时拥有指向前一个节点和后一个节点的指针D) 只能从链表的一端进行操作答案: C在链表中,删除一个节点的操作涉及修改哪些指针?A) 只需要修改被删除节点的前一个节点的指针B) 只需要修改被删除节点的后一个节点的指针C) 需要修改被删除节点的前一个节点和后一个节点的指针D) 不需要修改任何指针答案: C在链表的尾部添加一个新节点的操作复杂度是多少?A) O(1)B) O(n)C) O(log n)D) O(n^2)答案: A如何遍历链表的所有节点?A) 使用for循环B) 使用while循环C) 使用递归函数D) 使用if语句答案: B在链表中,如何找到特定值的节点?A) 使用线性搜索B) 使用二分搜索C) 使用递归搜索D) 使用栈搜索答案: A链表和数组相比,哪个更适合频繁插入和删除操作?A) 链表B) 数组C) 二叉树D) 堆栈答案: A在链表中,如何在指定位置插入一个新节点?A) 修改前一个节点的指针B) 修改后一个节点的指针C) 修改当前节点的指针D) 不需要修改任何指针答案: A链表的头指针指向什么?A) 链表的第一个节点B) 链表的最后一个节点C) 链表的中间节点D) 链表的空节点答案: A链表中节点的个数称为什么?A) 链表的长度B) 链表的高度C) 链表的宽度D) 链表的容量答案: A在链表中,如何删除指定值的节点?A) 修改前一个节点的指针B) 修改后一个节点的指针C) 修改当前节点的指针D) 不需要修改任何指针答案: A单链表的最后一个节点指向什么?A) 链表的第一个节点B) 链表的最后一个节点C) NULLD) 链表的中间节点答案: C双向链表相比于单向链表的优势是什么?A) 占用更少的内存空间B) 遍历速度更快C) 可以从任意方向遍历D) 插入和删除操作更快答案: C在链表中,如何找到倒数第n个节点?A) 遍历整个链表B) 使用递归函数C) 使用栈数据结构D) 使用双指针技巧答案: D链表的删除操作和数组的删除操作的时间复杂度分别是什么?A) 链表的删除操作为O(1),数组的删除操作为O(n)B) 链表的删除操作为O(n),数组的删除操作为O(1)C) 链表的删除操作为O(n),数组的删除操作为O(n)D) 链表的删除操作为O(1),数组的删除操作为O(1)答案: A在链表中,如何判断链表是否为空?A) 检查头指针是否为NULLB) 检查尾指针是否为NULLC) 检查链表的长度是否为0D) 检查链表的第一个节点是否为NULL答案: A链表的逆序操作是指什么?A) 删除链表中的节点B) 反转链表中节点的顺序C) 插入节点到链表的尾部D) 在链表中查找指定值的节点答案: B在链表中,如何查找指定值的节点?A) 使用线性搜索B) 使用二分搜索C) 使用递归搜索D) 使用栈搜索答案: A在双向链表中,如何删除指定值的节点?A) 修改前一个节点的指针B) 修改后一个节点的指针C) 修改当前节点的指针D) 不需要修改任何指针答案: A链表的插入操作和数组的插入操作的时间复杂度分别是什么?A) 链表的插入操作为O(1),数组的插入操作为O(n)B) 链表的插入操作为O(n),数组的插入操作为O(1)C) 链表的插入操作为O(n),数组的插入操作为O(n)D) 链表的插入操作为O(1),数组的插入操作为O(1)答案: A如何删除单向链表中的重复节点?A) 使用递归算法B) 使用双指针技巧C) 使用栈数据结构D) 不需要额外操作,链表会自动去重答案: B链表的优势之一是什么?A) 随机访问速度快B) 占用内存空间少C) 插入和删除操作高效D) 支持高级操作如排序和搜索答案: C在链表中,如何找到中间节点?A) 遍历整个链表B) 使用递归函数C) 使用栈数据结构D) 使用快慢指针技巧答案: D在链表中,如何在尾部添加一个新节点?A) 修改前一个节点的指针B) 修改后一个节点的指针C) 修改当前节点的指针D) 创建一个新节点并更新尾指针答案: D链表的查找操作的时间复杂度是多少?A) O(1)B) O(log n)C) O(n)D) O(n^2)答案: C在双向链表中,如何找到倒数第n个节点?A) 从头节点开始遍历B) 从尾节点开始遍历C) 使用递归函数D) 使用双指针技巧答案: B链表的删除操作的时间复杂度是多少?A) O(1)B) O(log n)C) O(n)D) O(n^2)答案: A链表和数组相比,哪个更适合频繁插入和删除操作?A) 链表B) 数组C) 哈希表D) 栈答案: A如何判断链表是否有环?A) 使用线性搜索B) 使用递归算法C) 使用快慢指针技巧D) 使用栈数据结构答案: C在链表中,如何反转链表的顺序?A) 使用递归算法B) 使用栈数据结构C) 使用双指针技巧D) 使用循环迭代答案: D在链表中,如何删除所有节点?A) 依次删除每个节点B) 修改头指针为NULLC) 修改尾指针为NULLD) 不需要额外操作,链表会自动清空答案: A链表的头节点是什么?A) 链表的第一个节点B) 链表的最后一个节点C) 链表的中间节点D) 链表的空节点答案: A在链表中,如何插入一个新节点到指定位置之前?A) 修改前一个节点的指针B) 修改后一个节点的指针C) 修改当前节点的指针D) 不需要修改任何指针答案: A在链表中,如何删除指定位置的节点?A) 修改前一个节点的指针B) 修改后一个节点的指针C) 修改当前节点的指针D) 不需要修改任何指针答案: A单向链表和双向链表的区别是什么?A) 单向链表只有一个指针指向下一个节点,双向链表有两个指针分别指向前一个节点和后一个节点B) 单向链表只能从头到尾遍历,双向链表可以从头到尾或者从尾到头遍历C) 单向链表只能在尾部添加节点,双向链表可以在头部和尾部都添加节点D) 单向链表只能包含整型数据,双向链表可以包含任意类型的数据答案: A链表的删除操作和数组的删除操作的时间复杂度分别是什么?A) 链表的删除操作为O(1),数组的删除操作为O(n)B) 链表的删除操作为O(n),数组的删除操作为O(1)C) 链表的删除操作为O(n),数组的删除操作为O(n)D) 链表的删除操作为O(1),数组的删除操作为O(1)答案: A如何判断两个链表是否相交?A) 比较链表的长度是否相等B) 比较链表的头节点是否相等C) 比较链表的尾节点是否相等D) 比较链表中的所有节点是否相等答案: B链表和数组的主要区别是什么?A) 链表是一种线性数据结构,数组是一种非线性数据结构B) 链表的长度可变,数组的长度固定C) 链表支持随机访问,数组只能顺序访问D) 链表的插入和删除操作效率高,数组的访问效率高答案: B在链表中,如何找到倒数第k个节点?A) 从头节点开始遍历,直到倒数第k个节点B) 从尾节点开始遍历,直到倒数第k个节点C) 使用递归函数查找倒数第k个节点D) 使用双指针技巧,一个指针先移动k步,然后两个指针同时移动直到第一个指针到达链表末尾答案: D在链表中,如何判断是否存在环?A) 使用线性搜索,检查是否有重复的节点B) 使用递归算法,判断节点是否已经访问过C) 使用栈数据结构,检查节点是否已经入栈D) 使用快慢指针技巧,如果两个指针相遇,则存在环答案: D如何将两个有序链表合并成一个有序链表?A) 创建一个新链表,依次比较两个链表的节点并插入新链表中B) 将第一个链表的尾节点指向第二个链表的头节点C) 将第二个链表的尾节点指向第一个链表的头节点D) 使用递归算法,依次比较两个链表的节点并合并答案: A在链表中,如何删除重复的节点?A) 使用递归算法,遍历链表并删除重复的节点B) 使用双指针技巧,依次比较相邻节点并删除重复的节点C) 使用栈数据结构,检查节点是否已经入栈并删除重复的节点D) 不需要额外操作,链表会自动去重答案: B链表的优点是什么?A) 占用内存空间少B) 插入和删除操作高效C) 支持高级操作如排序和搜索D) 可以随机访问任意位置的元素答案: B。
期末复习 第一章 绪论 复习1、计算机算法必须具备输入、输出、可行性、确定性、有穷性5个特性。
2、算法分析的两个主要方面是空间复杂度和时间复杂度。
3、数据元素是数据的基本单位。
4、数据项是数据的最小单位。
5、数据结构是带结构的数据元素的集合。
6、数据的存储结构包括顺序、链接、散列和索引四种基本类型。
数据结构算 法数据:计算机处理的信息总称数据项:最小单位 数据元素:最基本单位数据对象:元素集合数据结构:相互之间存在一种或多种特定关系的数据元素集合。
概念:数据元素之间的关系 线性结构:一对一非线性结构 树:一对多 图:多对多顺序存储结构 链表存储结构 索引。
散列。
算法描述:指令的有限有序序列有穷性 确定性 可行性 输入 输出 时间复杂度 空间复杂度第二章 线性表 复习1、在双链表中,每个结点有两个指针域,包括一个指向前驱结点的指针 、一个指向后继结点的指针2、线性表采用顺序存储,必须占用一片连续的存储单元3、线性表采用链式存储,便于进行插入和删除操作4、线性表采用顺序存储和链式存储优缺点比较。
5、简单算法第三章 栈和队列 复习定义逻辑关系:前趋 后继节省空间 随机存取 插、删效率低 插入 删除1、 栈和队列的异同点。
2、 栈和队列的基本运算3、 出栈和出队4、 基本运算第四章 串 复习存储结构栈的概念:在一端操作的线性表 运算算法栈的特点:先进后出 LIFO初始化 进栈push 出栈pop顺序队列 循环队列队列概念:在两端操作的线性表 假溢出链队列队列特点:先进先出 FIFO基本运算顺序:链队:队空:front=rear队满:front=(rear+1)%MAXSIZE队空:rear 初始化 判空 进队 出队取队首元素第五章 数组和广义表 复习定义:由n(≥1)个字符组成的有限序列 S=”c 1c 2c 3 ……cn ”串长度、空白串、空串。
紧缩格式 非紧缩格式以字节为单位的存储格式 (C 语言用数组或指针表示) 基本运算strlen(s) 串长度 strcat(s1,s2) 联接 strcmp(s1,s2) 比较 strcpy(s1,s2) 复制 strstr(s1,s2) 子串查询模式匹配失败链接值匹配算法单字符链表串 多字符链表串串变量的存储映像:串名、串值对应关系表顺序存储方式压缩存储方式行优先顺序存放列优先顺序存放C语言数组:行优先下标从[0]开始,公式变化稀疏矩阵应用表达式程序调用广义表定义:n(≥0)个元素的有限序列表头:Head(A)= a1概念:长度、深度、原子、子表表尾:Tail(A)=(a2,a3,…,a n)表结点特殊矩阵对称矩阵三角矩阵对角矩阵三元组存储:三元组m n t链表存储:十字链表原子结点第六章 树 复习1、三个结点可以组成2种不同形态的树。
C语言的循环链表和约瑟夫环C语言的循环链表和约瑟夫环约瑟夫问题)是一个数学的应用问题,对于学习C语言四非常挺有帮助的,下面是店铺为大家搜集整理出来的有关于C语言的循环链表和约瑟夫环,一起了解下吧!循环链表的实现单链表只有向后结点,当单链表的尾链表不指向NULL,而是指向头结点时候,形成了一个环,成为单循环链表,简称循环链表。
当它是空表,向后结点就只想了自己,这也是它与单链表的主要差异,判断node->next是否等于head。
代码实现分为四部分:1. 初始化2. 插入3. 删除4. 定位寻找代码实现:1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1void ListInit(Node *pNode){int item;Node *temp,*target;cout<<"输入0完成初始化"<<endl; cin="">>item;if(!item)return ;if(!(pNode)){ //当空表的时候,head==NULLpNode = new Node ;if(!(pNode))exit(0);//未成功申请pNode->data = item;pNode->next = pNode;}else{//for(target = pNode;target->next!=pNode;target = target->next);4 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3temp = new Node;if(!(temp))exit(0);temp->data = item;temp->next = pNode;target->next = temp;}}}void ListInsert(Node *pNode,int i){ //参数是首节点和插入位置Node *temp;Node *target;int item;cout<<"输入您要插入的值:"<<endl; cin="">>item;if(i==1){temp = new Node;if(!temp)exit(0);temp->data = item;for(target=pNode;target->next != pNode;target = target->next);temp->next = pNode;target->next = temp;pNode = temp;}else{target = pNode;for (int j=1;j<i-1;++j) target="target-">next;temp = new Node;if(!temp)exit(0);temp->data = item;temp->next = target->next;target->next = temp;}}void ListDelete(Node *pNode,int i){Node *target,*temp;if(i==1){for(target=pNode;target->next!=pNode;target=target ->next);temp = pNode;//保存一下要删除的首节点 ,一会便于释放6 37 38 39 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5pNode = pNode->next;target->next = pNode;temp;}else{target = pNode;for(int j=1;j<i-1;++j) target="target-">next;temp = target->next;//要释放的nodetarget->next = target->next->next;temp;}}int ListSearch(Node *pNode,int elem){ //查询并返回结点所在的位置Node *target;int i=1;for(target = pNode;target->data!=elem && target->next!= pNode;++i)target = target->next;if(target->next == pNode && target->data!=elem)return 0;else return i;}</i-1;++j)></i-1;++j)></endl;></endl;>5 96 0 6 1 6 2 6 3 6 4 6 5 6 6 67 68 69 7 0 7 1 7 2 7 3 7 4 7 5 7 6 7 7 7 8 7 9 8约瑟夫问题约瑟夫环(约瑟夫问题)是一个数学的'应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。
C语⾔基础⼊门:链表详解篇 链表是⼀种常见的重要的数据结构。
它是动态地进⾏存储分配的⼀种结构。
它可以根据需要开辟内存单元。
链表有⼀个“头指针”变量,以head表⽰,它存放⼀个地址。
该地址指向⼀个元素。
链表中每⼀个元素称为“结点”,每个结点都应包括两个部分: ⼀为⽤户需要⽤的实际数据,⼆为下⼀个结点的地址。
因此,head指向第⼀个元素:第⼀个元素⼜指向第⼆个元素;……,直到最后⼀个元素,该元素不再指向其它元素,它称为“表尾”,它的地址部分放⼀个“NULL”(表⽰“空地址”),链表到此结束。
链表的各类操作包括:学习单向链表的创建、删除、插⼊(⽆序、有序)、输出、排序(选择、插⼊、冒泡)、反序等等。
基本操作 1. 节点的构造 #include #include #include #defineLEN sizeof(struct stu)structstu{ //数据char num[10];char name[20];float score; //指针structstu*next;}; 2. 建⽴链表 struct stu *create(){ /structstu*head;structstu*p1, *p2; head = (struct stu *)malloc(LEN); head->next =NULL; p1 = head; p2 = (struct stu *)malloc(LEN); printf("输⼊个⼈信息:学籍号、姓名和总成绩\n"); scanf("%s%s%f",p2->num, p2->name, &p2->score); getchar(); while(strcmp(p2->num,"0") !=0){/* 执⾏结束后 1。
p2的next域为NULL. 2。
第⼀个节点的next域指向第⼆个节点的数据域 3。
数据结构C语言版上机报告:单链表序在数据结构课程中,单链表是一个重要的概念,也是C语言中常用的数据结构之一。
本次报告将深入探讨单链表的基本概念、操作方法以及应用场景,帮助读者更深入地理解和掌握这一数据结构。
一、概述1.1 单链表的定义单链表是一种线性表,它由一系列节点组成,每个节点包含两部分:数据域和指针域。
数据域用于存储数据元素,指针域用于指向下一个节点,通过指针将这些节点串联在一起,形成一个链表结构。
1.2 单链表的特点单链表具有以下特点:(1)动态性:单链表的长度可以动态地增加或减少,不需要预先分配固定大小的空间。
(2)插入和删除操作高效:在单链表中进行插入和删除操作时,只需要修改指针的指向,时间复杂度为O(1)。
(3)随机访问效率低:由于单链表采用链式存储结构,无法通过下标直接访问元素,需要从头节点开始依次遍历,时间复杂度为O(n)。
1.3 单链表的基本操作单链表的基本操作包括:创建、插入、删除、查找等。
这些操作是使用单链表时常常会涉及到的,下面将逐一介绍这些操作的具体实现方法和应用场景。
二、创建2.1 头插法和尾插法在C语言中,可以通过头插法和尾插法来创建单链表。
头插法是将新节点插入到链表的头部,尾插法是将新节点插入到链表的尾部,这两种方法各有优缺点,可以根据具体应用场景来选择。
2.2 应用场景头插法适合于链表的逆序建立,尾插法适合于链表的顺序建立。
三、插入3.1 在指定位置插入节点在单链表中,插入节点需要考虑两种情况:在链表头部插入和在链表中间插入。
通过对指针的操作,可以实现在指定位置插入节点的功能。
3.2 应用场景在实际应用中,经常会有需要在指定位置插入节点的情况,比如排序操作、合并两个有序链表等。
四、删除4.1 删除指定节点在单链表中,删除节点同样需要考虑两种情况:删除头节点和删除中间节点。
通过对指针的操作,可以实现删除指定节点的功能。
4.2 应用场景在实际应用中,经常会有需要删除指定节点的情况,比如删除链表中特定数值的节点等。
结构体与链表11.1 结构体类型的定义结构体是由C语言中的基本数据类型构成的、并用一个标识符来命名的各种变量的组合,其中可以使用不同的数据类型。
1.结构体类型的定义Struct结构体名{ 类型标识符1 成员名1;类型标识符2 成员名2;……类型标识符n 成员名n;};Struct结构体名——结构体类型名2.关于结构体类型的说明:(1)“struct 结构体名”是一个类型名,它和int、float等作用一样可以用来定义变量。
(2)结构体名是结构体的标识符不是变量名,也不是类型名。
(3)构成结构体的每一个类型变量称为结构体成员,它像数组的元素一样,单数组中元素以下标来访问,而结构体是按结构体变量名来访问成员的。
(4)结构体中的各成员既可以属于不同的类型,也可以属于相同的类型。
(5)成员也可以是一个结构体类型,如:Struct date{Int month;Int day;Int year;};Struct person{Float num;Char name[20];Char sex;Int age;Struct date birthday;Char address[10];};11.2 结构体类型变量11.2.1 结构体类型变量的定义1.先定义结构体类型,再定义结构体变量形式:Struct 结构体名{类型标识符1 成员名1;类型标识符2 成员名2;……类型标识符n 成员名n;};Struct 结构体名变量名表;例如:Struct student{char name[20];Char sex;Int age;Float score;};Struct student stu1,stu2;2.在定义结构体类型的同时定义变量形式:Struct 结构体名{类型标识符1 成员名1;类型标识符2 成员名2;……类型标识符n 成员名n;}变量名表;例如:Struct student{Char name[20];Char sex;Int age;Float score;}stu1,stu2;3.用匿名形式直接定义结构体类型变量形式:Struct{类型标识符1 成员名1;类型标识符2 成员名2;……类型标识符n 成员名n;}变量名表;例如:StructChar naem[20];Char sex;Int age;Float score;}stu1,stu2;11.2.2 结构体变量的使用结构体是一种新的数据类型,因此结构体变量也可以像其它类型的变量一样赋值、运算,不同的是结构体变量以成员作为基本变量。
链表专题复习数组作为存放同类数据的集合;给我们在程序设计时带来很多的方便;增加了灵活性..但数组也同样存在一些弊病..如数组的大小在定义时要事先规定;不能在程序中进行调整;这样一来;在程序设计中针对不同问题有时需要3 0个元素大小的数组;有时需要5 0个数组元素的大小;难于统一..我们只能够根据可能的最大需求来定义数组;常常会造成一定存储空间的浪费..我们希望构造动态的数组;随时可以调整数组的大小;以满足不同问题的需要..链表就是我们需要的动态数组..它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间;决不构成对存储区的浪费..链表是一种复杂的数据结构;其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表;下面只介绍单向链表..7.4.1 单链表图7 - 3是单链表的结构..单链表有一个头节点h e a d;指向链表在内存的首地址..链表中的每一个节点的数据类型为结构体类型;节点有两个成员:整型成员实际需要保存的数据和指向下一个结构体类型节点的指针即下一个节点的地址事实上;此单链表是用于存放整型数据的动态数组..链表按此结构对各节点的访问需从链表的头找起;后续节点的地址由当前节点给出..无论在表中访问那一个节点;都需要从链表的头开始;顺序向后查找..链表的尾节点由于无后续节点;其指针域为空;写作为N U L L..图7 - 3还给出这样一层含义;链表中的各节点在内存的存储地址不是连续的;其各节点的地址是在需要时向系统申请分配的;系统根据内存的当前情况;既可以连续分配地址;也可以跳跃式分配地址..看一下链表节点的数据结构定义:struct node{int num;struct node p;} ;在链表节点的定义中;除一个整型的成员外;成员p是指向与节点类型完全相同的指针..在链表节点的数据结构中;非常特殊的一点就是结构体内的指针域的数据类型使用了未定义成功的数据类型..这是在C中唯一规定可以先使用后定义的数据结构..单链表的创建过程有以下几步:1 定义链表的数据结构..2 创建一个空表..3 利用m a l l o c 函数向系统申请分配一个节点..4 将新节点的指针成员赋值为空..若是空表;将新节点连接到表头;若是非空表;将新节点接到表尾..5 判断一下是否有后续节点要接入链表;若有转到3 ;否则结束..单链表的输出过程有以下几步1 找到表头..2 若是非空表;输出节点的值成员;是空表则退出..3 跟踪链表的增长;即找到下一个节点的地址..4 转到2 ..下列是用尾插法创建链表新开辟的节点总是插在表末例7-5 创建一个存放正整数输入负数时做结束标志的单链表;并打印输出..include <stdlib.h> /包含ma l l o c 的头文件/include <stdio.h>struct node /链表节点的结构 /{int num;struct node next; } ;m a i n{struct node creat; / 函数声明 /void print;struct node head; / 定义头指针 /head=NULL;/建一个空表/head=creathead;/创建单链表/printhead;/打印单链表/ }//struct nodecreatstructnodehead函/数返回的是与节点相同类型的指针/{struct nodep1;p2;p1=p2=structnodemallocsizeofstructnode;申请/新节点/scanf"%d";&p1->num;/输入节点的值/p1->next=NULL;/将新节点的指针置为空/whilep1->num>0/输入节点的数值大于0/{ifhead==NULLhead=p1;/空表;接入表头/elsep2->next=p1;/非空表;接到表尾/p2=p1;p1=structnodemallocsizeofstructnode;申/请下一个新节点/scanf"%d";&p1->num;/输入节点的值/}return head;/返回链表的头指针/ }//void printstruct nodehead输/出以head为头的链表各节点的值/{struct node temp;temp=head;/取得链表的头指针/whiletemp=NULL/只要是非空表/{printf"%6d";temp->num;/输出链表节点的值/temp=temp->next;/跟踪链表增长/ } }在链表的创建过程中;链表的头指针是非常重要的参数..因为对链表的输出和查找都要从链表的头开始;所以链表创建成功后;要返回一个链表头节点的地址;即头指针..下列是用头插法创建链表新开辟的结点总是作为表头结点程序清单位:include <stdio.h>include <stdlib.h>struct node{ int num;struct node next; };struct node creatstruct node head{ struct node top; /top为新开辟的结点/top=struct node mallocsizeofstruct node;scanf“%d”;&top->num;whiletop->num>=0{top->next=head; /原来的第一个结点接在新开辟的结点后面/head=top; /新开辟结点作表头结点;也就是说插在表头/top=struct node mallocsizeofstruct node;scanf“%d”;&top->num; }return head; }7.4.2 单链表的插入与删除在链表这种特殊的数据结构中;链表的长短需要根据具体情况来设定;当需要保存数据时向系统申请存储空间;并将数据接入链表中..对链表而言;表中的数据可以依此接到表尾或连结到表头;也可以视情况插入表中;对不再需要的数据;将其从表中删除并释放其所占空间;但不能破坏链表的结构..这就是下面将介绍的链表的插入与删除..1. 链表的删除在链表中删除一个节点;用图7 - 4描述如下:例7-6 创建一个学生学号及姓名的单链表;即节点包括学生学号、姓名及指向下一个节点的指针;链表按学生的学号排列..再从键盘输入某一学生姓名;将其从链表中删除..首先定义链表的结构:从图7 - 4中看到;从链表中删除一个节点有三种情况;即删除链表头节点、删除链表的中间节点、删除链表的尾节点..题目给出的是学生姓名;则应在链表中从头到尾依此查找各节点;并与各节点的学生姓名比较;若相同;则查找成功;否则;找不到节点..由于删除的节点可能在链表的头;会对链表的头指针造成丢失;所以定义删除节点的函数的返回值定义为返回结构体类型的指针..struct node deletstruct node head;char pstr/he a d 为头指针;删除ps t r 所在节点/{struct node temp;p;t e m p = h e a d ; / 链表的头指针 /if head==NULL / 链表为空 /printf"\nList is null\n";else /非空表 /{t e m p = h e a d ;while strcmptemp->str;pstr=0&&temp->next=NULL/ 若节点的字符串与输入字符串不同;并且未到链表尾 /{p = t e m p ;t e m p = t e m p - > n e x t ; / 跟踪链表的增长;即指针后移 / }ifstrcmptemp->str;pstr==0 / 找到字符串 /{iftemp==head { / 表头节点 /printf"delete string :%s\n";temp->str;h e a d = h e a d - > n e x t ;f r e e t e m p ; / 释放被删节点 /}e l s e{p->next=temp->next; /表中节点/printf"delete string :%s\n";temp->str;f r e e t e m p ;} }else printf"\nno find string\n"; /没找到要删除的字符串/}r e t u r n h e a d ; / 返回表头指针 / }2. 链表的插入首先定义链表的结构:struct{ int num; /学生学号 /char str20; /姓名 /struct node next; } ;在建立的单链表中;插入节点有三种情况;如图7 - 5所示..插入的节点可以在表头、表中或表尾..假定我们按照以学号为顺序建立链表;则插入的节点依次与表中节点相比较;找到插入位置..由于插入的节点可能在链表的头;会对链表的头指针造成修改;所以定义插入节点的函数的返回值定义为返回结构体类型的指针..节点的插入函数如下:struct node inserthead;pstr;n / 插入学号为n、姓名为p s t r 的节点 /struct node head; / 链表的头指针 /char pstr;int n;{ struct node p1;p2;p3;p1=struct nodemallocsizeofstruct node分;配/一个新节点/s t r c p y p 1 - > s t r ; p s t r ; / 写入节点的姓名字串 / p 1 - > n u m = n ; / 学号 /p 2 = h e a d ;if head==NULL / 空表 /{head=p1; p1->next=NULL;/ 新节点插入表头 /}e l s e{ /非空表 /whilen>p2->num&&p2->next=NULL/ 输入的学号小于节点的学号;并且未到表尾 /{p 3 = p 2 ;p 2 = p 2 - > n e x t ; / 跟踪链表增长 /}if n<=p2->num / 找到插入位置 /if head==p2 / 插入位置在表头 /{h e a d = p 1 ;p 1 - > n e x t = p 2 ;}e l s e{ /插入位置在表中 /p 3 - > n e x t = p 1 ;p 1 - > n e x t = p 2 ;}e l s e{ /插入位置在表尾 /p 2 - > n e x t = p 1 ;p 1 - > n e x t = N U L L ;}}r e t u r n h e a d ; / 返回链表的头指针 / }3. 实例例7 - 7创建包含学号、姓名节点的单链表..其节点数任意个;表以学号为序;低学号的在前;高学号的在后;以输入姓名为空作结束..在此链表中;要求删除一个给定姓名的节点;并插入一个给定学号和姓名的节点..include "stdlib.h"include "malloc. h"struct node /节点的数据结构 /{int num;char str20;struct node next; } ;main{ / 函数声明 /struct node creat;struct node insert;struct node delet;void print ;struct node head;char str20;int n;head=NULL; /做空表 /head=creat head; / 调用函数创建以head 为头的链表 / p r i n t h e a d ;/ 调用函数输出节点 / printf"\n input inserted num;name:\n";getsstr; /输入学号 /n=atoi str;getsstr; /输入姓名 /head=insert head; str; n; 将/节点插入链表/print head; / 调用函数输出节点/printf"\n input deleted name:\n";getsstr; /输入被删姓名 /head=delethead;str; /调用函数删除节点/ print head; /调用函数输出节点 /r e t u r n ; }/ 创建链表 /struct node creatstruct node head{char temp30;struct node pl;p2;pl=p2=struct node mallocsizeofstruct node; printf "input num; name: \n;"printf"exit:double times Enter\n";g e t s t e m p ;gets p1->str;pl->num=atoi temp;p l - > n e x t = N U L L ;while strlen pl->str>0{if head==NULL head=pl;else p2->next=p1;P 2 = p l ;pl=struct node mallocsizeofstruct node; printf "input num; name: \n";printf"exit:double times Enter\n";g e t s t e m p ;getspl ->str;p1->num=atoi temp;p1 - > n e x t = N U L L ; }return head; }/ 插入节点 /struct node insert head; pstr;n;struct node head;char pstr;int n;{ struct node pl;p2;p3;p1=struct nodemallocsizeofstruct node; strcpy p1->str; pstr;p 1 - > n u m = n ;p 2 = h e a d ;i f h e a d = = N U L L{h e a d = p l ; p l - > n e x t = N U L L ;}e l s e{while n>p2->num&&p2->next=NULL {p 3 = P 2p 2 = p 2 - > n e x t ; } if n<=p2->numif head==p2{h e a d = p l ;p l - > n e x t = p 2 ; } else{p 3 - > n e x t = p l ;p l - > n e x t = p 2 ; } else{p 2 - > n e x t = p l ;p l - > n e x t = N U L L ;} }r e t u r n h e a d ; }/ 删除节点 /struct node delet struct node head; char pstr{struct node temp;p;t e m p = h e a d ;if head==NULLprintf"\nList is null\n";else{ t e m p = h e a d ;while strcmptemp->str;pstr=O&&temp->next=NULL{p = t e m p ;t e m p = t e m p - > n e x t ;}i f s t r c m p t e m p - > s t r ; p s t r = = 0 {if temp== head{h e a d = h e a d - > n e x t ;f r e e t e m p ;}else{p->next =temp->next;printf"delete string :%s\n";temp->str;f r e e t e m p ;} }else printf"\nno find string\n";}returnhead; }/ 链表各节点的输出 /void print struct node head{struct node temp;t e m p = h e a d ;while temp=NULL{p r i n t f " \ n % d - - - - % s \ n " ; t e m p - > n u m ;t e m p - > s t r ;t e m p = t e m p - > n e x t ; }r e t u r n ; }带头结点与不带头结点链表的区别:题目中没说明;就当不带头结点;除非明确规定了带头结点..带头结点的链表的第一个结点没有数据域;只有指针域..例如要计算链表中所有结点数据的和;应定义一个指向结构体结点的指针;指向链表的第一个含数据的结点;给它赋值时;应是 struct node p=head->next; 其中head为链表的头指针..因为头结点不含数据;头结点指向的结点才开始带数据..如果是不带头结点的链表;第一个结点就含数据;因此;给它赋值时;应是struct node p=head;附:常见算法用链表实现1.查找算法例:如果有如下链表结构:struct st{ char name20; /学生姓名/int cj; /学生成绩/struct st next; };如果链表已创建正确;要求输入一个学生姓名;查找该生成绩;并输出该生姓名;成绩;以及该生在链表中的位置第几个结点struct st searchstruct st h;char x{ struct st p=h;int flag=0;position=0;whilep=NULL{ position++;ifstrcmpp->name;x==0 {flag=1;break;}p=p->next; }ifflag==1{printf“在链表中的第%d个结点”;position;return p; } /找到了;返回该结点的地址/else{ printf“no found”; return ;} }main{ struct st q;head;char xm20;getsxm;head=creatNULL; /链表已创建;题目已规定;创建链表过程省略/ q=searchhead;xm;printf“%s: %d\n”;q->name;q->cj; }2.排序算法欲将链表中结点的成绩从大到小排列输出..include <stdlib.h>include <stdio.h>struct st{ int cj;struct st link; };void sortstruct st head{struct st p;q;int t;forp=head;p=NULL;p=p->linkforq=p->link;q=NULL;q=q->linkifq->cj>p->cj {t=p->cj;p->cj=q->cj;q->cj=t;} }注意:由于链表中结点在内存中是不连续的;故不可使用p++指针自增;指向链表的下一个结点;只能通过p=p->link指向下一个结点..单向链表只能从当前结点找到表尾方向的下一个结点;不可从当前结点找到表头方向的前一个结点..因为当前结点只存放了下一个结点的地址..。
一、链表的基本概念和结构链表是一种常用的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
在C语言中,链表通常由结构体来实现。
一个链表节点包含两个部分:数据域和指针域。
数据域用于存储数据,指针域用于存储指向下一个节点的指针。
二、链表的创建和初始化链表的创建和初始化是链表操作的基础。
在C语言中,可以通过定义结构体类型和函数来实现链表的创建和初始化。
例如,下面的代码演示了如何定义一个链表节点类型和创建一个空的链表:```c#include <stdio.h>#include <stdlib.h>typedef struct Node {int data;struct Node* next;struct Node* prev;} Node;Node* createList() {Node* head = NULL;return head;}```三、链表节点的插入和删除链表节点的插入和删除是链表操作中最常见的操作之一。
在C语言中,可以通过函数来实现链表节点的插入和删除。
例如,下面的代码演示了如何在链表末尾插入一个节点和从链表中删除一个节点:```cNode* insertNode(Node* head, int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;newNode->prev = head;if (head == NULL) {head = newNode;} else {Node* current = head;while (current->next != NULL) {current = current->next;}current->next = newNode;}return head;}Node* deleteNode(Node* head, Node* node) {if (head == NULL || node == NULL) {return head;}if (head == node) {head = head->next;free(node);return head;}Node* current = head;while (current->next != NULL && current->next != node) { current = current->next;}if (current->next == node) {current->next = node->next;free(node);}return head;}```。
链表专题复习数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性。
但数组也同样存在一些弊病。
如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个元素大小的数组,有时需要5 0个数组元素的大小,难于统一。
我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费。
我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要。
链表就是我们需要的动态数组。
它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间,决不构成对存储区的浪费。
链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面只介绍单向链表。
7.4.1 单链表图7 - 3是单链表的结构。
单链表有一个头节点h e a d,指向链表在内存的首地址。
链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。
链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。
无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。
链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。
图7 - 3还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。
看一下链表节点的数据结构定义:struct node{int num;struct node *p;} ;在链表节点的定义中,除一个整型的成员外,成员p是指向与节点类型完全相同的指针。
在链表节点的数据结构中,非常特殊的一点就是结构体内的指针域的数据类型使用了未定义成功的数据类型。
这是在C中唯一规定可以先使用后定义的数据结构。
•单链表的创建过程有以下几步:1 ) 定义链表的数据结构。
2 ) 创建一个空表。
3 ) 利用m a l l o c ( )函数向系统申请分配一个节点。
4 ) 将新节点的指针成员赋值为空。
若是空表,将新节点连接到表头;若是非空表,将新节点接到表尾。
5 ) 判断一下是否有后续节点要接入链表,若有转到3 ),否则结束。
•单链表的输出过程有以下几步1) 找到表头。
2) 若是非空表,输出节点的值成员,是空表则退出。
3 ) 跟踪链表的增长,即找到下一个节点的地址。
4) 转到2 )。
下列是用尾插法创建链表新开辟的节点总是插在表末[例7-5] 创建一个存放正整数(输入负数时做结束标志)的单链表,并打印输出。
#include <stdlib.h> /包*含ma l l o c ( ) 的头文件*/#include <stdio.h>struct node /*链表节点的结构* /{int num;struct node *next; } ;m a i n ( ){struct node *creat(); / *函数声明* /void print();struct node *head; / * 定义头指针* /head=NULL;/*建一个空表*/head=creat(head);/*创建单链表*/print(head);/*打印单链表*/ }/******************************************/struct node*creat(structnode*head)函/数*返回的是与节点相同类型的指针*/ {struct node*p1,*p2;p1=p2=(structnode*)malloc(sizeof(structnode));申请/*新节点*/scanf("%d",&p1->num);/*输入节点的值*/p1->next=NULL;/*将新节点的指针置为空*/while(p1->num>0)/*输入节点的数值大于0*/{if(head==NULL)head=p1;/*空表,接入表头*/elsep2->next=p1;/*非空表,接到表尾*/p2=p1;p1=(structnode*)malloc(sizeof(structnode));申/请*下一个新节点*/scanf("%d",&p1->num);/*输入节点的值*/}return head;/*返回链表的头指针*/ }/*******************************************/void print(struct node*head)输/*出以head为头的链表各节点的值*/{struct node *temp;temp=head;/*取得链表的头指针*/while(temp!=NULL)/*只要是非空表*/{printf("%6d",temp->num);/*输出链表节点的值*/temp=temp->next;/*跟踪链表增长*/ } }在链表的创建过程中,链表的头指针是非常重要的参数。
因为对链表的输出和查找都要从链表的头开始,所以链表创建成功后,要返回一个链表头节点的地址,即头指针。
下列是用头插法创建链表新开辟的结点总是作为表头结点程序清单位:#include <stdio.h>#include <stdlib.h>struct node{ int num;struct node *next; };struct node *creat(struct node *head){ struct node *top; /*top为新开辟的结点*/top=(struct node *)malloc(sizeof(struct node));scanf(“%d”,&top->num);while(top->num>=0){top->next=head; /*原来的第一个结点接在新开辟的结点后面*/head=top; /*新开辟结点作表头结点,也就是说插在表头*/top=(struct node *)malloc(sizeof(struct node));scanf(“%d”,&top->num); }return head; }7.4.2 单链表的插入与删除在链表这种特殊的数据结构中,链表的长短需要根据具体情况来设定,当需要保存数据时向系统申请存储空间,并将数据接入链表中。
对链表而言,表中的数据可以依此接到表尾或连结到表头,也可以视情况插入表中;对不再需要的数据,将其从表中删除并释放其所占空间,但不能破坏链表的结构。
这就是下面将介绍的链表的插入与删除。
1. 链表的删除在链表中删除一个节点,用图7 - 4描述如下:[例7-6] 创建一个学生学号及姓名的单链表,即节点包括学生学号、姓名及指向下一个节点的指针,链表按学生的学号排列。
再从键盘输入某一学生姓名,将其从链表中删除。
首先定义链表的结构:从图7 - 4中看到,从链表中删除一个节点有三种情况,即删除链表头节点、删除链表的中间节点、删除链表的尾节点。
题目给出的是学生姓名,则应在链表中从头到尾依此查找各节点,并与各节点的学生姓名比较,若相同,则查找成功,否则,找不到节点。
由于删除的节点可能在链表的头,会对链表的头指针造成丢失,所以定义删除节点的函数的返回值定义为返回结构体类型的指针。
struct node *delet(struct node *head,char *pstr)/*he a d 为头指针,删除ps t r 所在节点*/{struct node *temp,*p;t e m p = h e a d ; / * 链表的头指针* /if (head==NULL) / *链表为空* /printf("\nList is null!\n");else /*非空表* /{t e m p = h e a d ;while (strcmp(temp->str,pstr)!=0&&temp->next!=NULL)/ * 若节点的字符串与输入字符串不同,并且未到链表尾* /{p = t e m p ;t e m p = t e m p - > n e x t ; / * 跟踪链表的增长,即指针后移* /}if(strcmp(temp->str,pstr)==0 ) / *找到字符串* /{if(temp==head) { / * 表头节点* /printf("delete string :%s\n",temp->str);h e a d = h e a d - > n e x t ;f r e e ( t e m p ) ; / *释放被删节点* /}e l s e{p->next=temp->next; /*表中节点*/printf("delete string :%s\n",temp->str);f r e e ( t e m p ) ;} }else printf("\nno find string!\n"); /*没找到要删除的字符串*/}r e t u r n ( h e a d ) ; / *返回表头指针* / }2. 链表的插入首先定义链表的结构:struct{ int num; /*学生学号* /char str[20]; /*姓名* /struct node *next; } ;在建立的单链表中,插入节点有三种情况,如图7 - 5所示。
插入的节点可以在表头、表中或表尾。
假定我们按照以学号为顺序建立链表,则插入的节点依次与表中节点相比较,找到插入位置。
由于插入的节点可能在链表的头,会对链表的头指针造成修改,所以定义插入节点的函数的返回值定义为返回结构体类型的指针。
节点的插入函数如下:struct node *insert(head,pstr,n) / *插入学号为n、姓名为p s t r 的节点* / struct node *head; / *链表的头指针* /char *pstr;int n;{ struct node *p1,*p2,*p3;p1=(struct node*)malloc(sizeof(struct node))分;配/*一个新节点*/s t r c p y ( p 1 - > s t r , p s t r ) ; / * 写入节点的姓名字串* /p 1 - > n u m = n ; / * 学号* /p 2 = h e a d ;if (head==NULL) / * 空表* /{head=p1; p1->next=NULL;/ *新节点插入表头* /}e l s e{ /*非空表* /while(n>p2->num&&p2->next!=NULL)/ *输入的学号小于节点的学号,并且未到表尾* /{p 3 = p 2 ;p 2 = p 2 - > n e x t ; / * 跟踪链表增长* /}if (n<=p2->num) / *找到插入位置* /if (head==p2) / * 插入位置在表头* /{h e a d = p 1 ;p 1 - > n e x t = p 2 ;}e l s e{ /*插入位置在表中* /p 3 - > n e x t = p 1 ;p 1 - > n e x t = p 2 ;}e l s e{ /*插入位置在表尾* /p 2 - > n e x t = p 1 ;p 1 - > n e x t = N U L L ;}}r e t u r n ( h e a d ) ; / * 返回链表的头指针* / }3. 实例[例7 - 7 ]创建包含学号、姓名节点的单链表。