C语言 day20 | 我的日常分享

C语言 day20

链表

  1. 链表的基本概念
  2. 单向链表的操作
  3. 其他链表的概念及应用

链表的基本概念

  • 定义:链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现一种线性的存储结构。

  • 特点:链表是由咦嘻嘻额的节点(链表中每一个元素称为节点)组成,节点在运行时动态生成(malloc/calloc),每个节点包括两个部分:

    • 一个是存储数据的数据域
    • 另一个是存储下一个节点地址的指针域
  • 链表的构成:

图片

图片

拓展:数组分为静态数组和动态数组




链表节点的定义(结构体实现)

1
2
3
4
5
6
7
8
9
10
//定义节点
typedef struct stu{
//数据域(自定义)
int num;
char name[32];
float score;

//指针域
struct stu *next;
}STU;



静态链表(玩玩)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
typedef struct stu{
int num;
char name[32];
float score;
struct stu *next;
}STU;
int main(int argc,char *argv[])
{
STU data1={100,"lucy",60};
STU data2={101,"bob",87};
STU data3={102,"mack",65};
STU data4={103,"jane",93};

//链表头
STU *head=NULL;
head=&data1;
data1.next=&data2;
data2.next=&data3;
data3.next=&data4;
data4.next=NULL;

//遍历链表 链表头head永远不要动,定义个变量来存它
STU *pb=head;
while(pb != NULL){
printf("num=%d name=%s score=%f\n",pb->num,pb->name,pb->score);
pb=pb->next;//重要,将pb移动到下一个节点
}

return 0;
}

运行结果:
图片




动态链表(分文件、分函数实现)

案例:学生信息系统
main.c link.c link.h

1、布局整个程序框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void stu_help(void);

int main(int argc, char* argv[]) {

//打印帮助信息
stu_help();
//获取输入指令
while (1) {
char cmd[32] = "";
printf("请输入操作指令:\n");
scanf("%s", cmd);
if (strcmp(cmd, "help") == 0)
{
stu_help();
}
else if(strcmp(cmd, "insert") == 0){
printf("-------inset--------\n");
}
else if (strcmp(cmd, "print") == 0) {
printf("-------print--------\n");
}
else if (strcmp(cmd, "delete") == 0) {
printf("-------delete--------\n");
}
else if (strcmp(cmd, "free") == 0) {
printf("-------free--------\n");
}
else if (strcmp(cmd, "quit") == 0) {
break;
}
}
return 0;
}

void stu_help(void) {
printf("###################################\n");
printf("#help:打印帮助信息 #\n");
printf("#insert:插入链表节点 #\n");
printf("#print:遍历链表节点信息 #\n");
printf("#search:查询链表节点 #\n");
printf("#delete:删除链表节点 #\n");
printf("#free:释放链表 #\n");
printf("#quit:退出 #\n");
printf("###################################\n");
return;
}

2、insert功能实现

1、链表插入之头部之前插入

link.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//#pragma once
//防止头文件重复包含
#ifndef __LINK_H__
#define __LINK_H__

//链表节点类型定义
typedef struct stu {
//数据域
int num;
char name[32];
float score;

//指针域
struct stu* next;
}STU;
extern STU* insert_link(STU* head, STU tmp);
extern void pritn_link(STU* head);

#endif // !__LINK_H__


link.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include"link.h"
#include<stdio.h>//NULL
#include<stdlib.h>//calloc

STU* insert_link(STU* head, STU tmp) {
//1、从堆区申请一个待插入的节点空间
STU* pi = (STU*)calloc(1, sizeof(STU));
if (pi == NULL) {
perror("calloc");
return head;//不要返回NULL
}

//2、将tmp的值赋给*pi
*pi = tmp;
pi->next = NULL;

//3、将pi插入到链表中(链表存在/链表不存在)
if (head == NULL) {//链表不存在
head = pi;
}
else {//链表存在
//1、让pi的指针域指向旧的头
pi->next = head;

//2、将head指向新的头节点
head = pi;
}

return head;

}

void pritn_link(STU *head){
if (head == NULL) {
printf("链表不存在\n");
return;
}
else
{
//在对链表的操作 不要轻易的让链表头动
STU* pb = head;
while (pb != NULL) {
printf("num=%d name=%s score=%f\n", pb->num, pb->name, pb->score);
pb = pb->next;//重要
}

}
return;
}

运行结果:
图片

2、链表插入之尾部插入

link.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//链表的尾部插入
STU* insert_link(STU* head, STU tmp) {
//1、从堆区申请一个待插入的节点空间
STU* pi = (STU*)calloc(1, sizeof(STU));
if (pi == NULL) {
perror("calloc");
return head;//不要返回NULL
}

//2、将tmp的值赋给*pi
*pi = tmp;
pi->next = NULL;

//3、将pi插入到链表的尾部(链表存在/链表不存在)
if (head == NULL) {//链表不存在
head = pi;
}
else {//链表存在
//a、寻找尾节点
STU* pb = head;
while (pb->next != NULL) {
pb = pb->next;
}
//b、尾节点pb链接上pi
pb->next = pi;
return head;
}

return head;

}

4、链表的有序插入

以num的顺序从小到大插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//链表的有序插入
STU* insert_link(STU* head, STU tmp) {
//1、从堆区申请一个待插入的节点空间
STU* pi = (STU*)calloc(1, sizeof(STU));
if (pi == NULL) {
perror("calloc");
return head;//不要返回NULL
}

//2、将tmp的值赋给*pi
*pi = tmp;
pi->next = NULL;

//3、将pi插入到链表的尾部(链表存在/链表不存在)
if (head == NULL) {//链表不存在
head = pi;
}
else {//链表存在
//a、寻找插入点
STU* pb = head, * pf = head;
while (pi->num > pb->num && pb->next!=NULL) {//pb->next!=NULL 防止越界,造成段错误
pf = pb;
pb = pb->next;
}
//b、判断插入点
if (pi->num <= pb->num) {//中部 或 头部
if (pb == head) {//头部
pi->next = head;
head = pi;
return head;
}
else//中部
{
pi->next = pb;
pf->next = pi;
return head;
}
}
else if (pi->num > pb->num && pb->next == NULL)//尾部
//else//尾部
{
pb->next = pi;
return head;
}
}
return head;
}