国庆节快乐呀。
今天在学链表,下面是我个人对链表的理解:
链表是结构体中存放一个指针,使之指向下一个结构体的数据结构。
小明在打开鞋柜的之后,拿出了a同学的鞋子,同时又发现一张纸条,是b同学鞋柜号码。这样b同学就可以不用给小明纸条,也能拿到自己的鞋子。
因为是结构体,鞋柜里不一定只有纸条,还可能有书本,水杯等东西。但存放这些东西的还是鞋柜。
想要遍历链表,只需要一扇一扇地打开鞋柜,顺着纸条找下一个鞋柜,就行了。
插入结点的时候,将前鞋柜的纸条放入此鞋柜,写一张此鞋柜的纸条放入前鞋柜。成为一条链。想象一下过程,其实很简单。
删除结点的时候,将此鞋柜的纸条放入前鞋柜,清空,就行了。
寻找结点,就是在遍历的时候打开鞋柜看一眼,看见目标鞋子就停下。
基础知识:
1.链表与结点不同,并不是一开始就分配好内存。链表在增加结点的时候需要用<malloc>库里面的malloc函数分配内存。
2.用typedef对结构体重命名,可以增加可读性,提高编码速度
3.结点分为数据域和指针域,数据域负责存储数据,指针域赋值为结点指引方向
4.尾结点的后继结点是空结点
以下是代码(参考了各位csdn大佬)侵删
c语言链表详解(超详细)_Endeavor_G的博客-CSDN博客_c语言链表https://blog.csdn.net/Endeavor_G/article/details/80552680(4条消息) ❤️《画解数据结构》七个动图,画解链表❤️_英雄哪里出来-CSDN博客https://blog.csdn.net/WhereIsHeroFrom/article/details/119381711
#include <stdio.h>
#include <malloc.h>
typedef struct student {
int score;
struct student* next;
}Linklist;
下面是函数:
首先是创建链表,这里我使用的是尾插法。尾插法就是:当一个新结点插入的时候,它会站到现在的尾结点后面,喊一声“我才是尾结点”,然后它就成新尾结点了。
Linklist* create(int n) {
Linklist* head, * node, * end;
head = (Linklist*)malloc(sizeof(Linklist));
end = head;
end->next = NULL;
for (int i = 0; i < n; i++) {
node = (Linklist*)malloc(sizeof(Linklist));
scanf_s("%d", &node->score);
end->next = node; //第二个结点是node
end = node; //尾结点变成这个node
}
end->next = NULL;
return head;
}
接着是销毁链表
为了便于自己理解,我把nextnode和temp想象成逃跑者与帮助逃跑者。请留意一下销毁链表与清空链表的不同。
//销毁链表
void destroy(Linklist* list) {
if (list == NULL) {
return;
} //若本来就为空,返回(不清空头结点)
Linklist* temp = list->next;//游标指针temp,
while (temp != NULL) {
Linklist* nextnode = temp->next; //用nextnode帮助temp逃逸,
free(temp); //释放temp足迹
temp = nextnode; //temp逃逸
}
//释放头结点
free(list);
//重新置空头结点指针
list = NULL;
下面是清空链表:
//清空链表
void clear(Linklist* list) {
if (list == NULL) {
return;
}
Linklist* temp = list->next;
while (temp != NULL) {
Linklist* nextnode = temp->next;
free(temp);
temp = nextnode;
}
list->next = NULL;
}
清空链表释放头结点的后继结点,而销毁链表不仅要释放头结点的后继结点,还要释放头结点。销毁链表后,除非再初始化一次链表,否则是无法写入任何数据的。
改变结点的值:
先在链表中寻找第n个结点,然后给出scanf函数更改它的值
//改变结点
void change(Linklist* list, int n) {
Linklist* temp = list; // 游标指针temp指向list
int i = 0;
while (i < n && temp != NULL) { //寻找第n个节点
temp = temp->next;
i++;
}
if (temp != NULL) {
scanf_s("%d", &temp->score);
}
else {
puts("no this node");
}
}
删除结点:
要设置一个in跟踪t(成为t的前驱结点),在删除t的时候便于将t的前驱和后继结点相连接起来。
void delet(Linklist* list, int n) {
Linklist* t = list;
Linklist* in=NULL;
int i = 0;
while (i < n && t != NULL) {
in = t; //in是t的前驱结点
t = t->next;
i++;
}
if (t != NULL) {
in->next = t->next;//找到了t,释放,in指向t的后继结点
free(t);
}
else {
puts("no this node");
}
}
插入结点:
这里使用的是后插法,也就是插到n的后面。
先找到结点n,设置它的插入结点in,给in输入score。
插入的时候,让in指向n的后继结点,让n指向in就行了。
//插入结点
void insert(Linklist* list, int n) {
Linklist* t = list, * in;
int i = 0;
while (i < n && t != NULL) {
t = t->next;
i++;
}
if (t != NULL) {
in = (Linklist*)malloc(sizeof(Linklist));
scanf_s("%d", &in->score);
in->next = t->next;
t->next = in;
}
else {
puts("no this node");
}
}
查询结点:
查询结点需要返回,而且返回类型是Linklist*
//查询结点
Linklist* getnode(Linklist* list, int n) {
Linklist* temp = list;//设置游标指针
int i = 0;
while (temp != NULL && i < n) {
temp = temp->next;
++i;
}
if (temp == NULL || i > n) {
printf("no this node");
return NULL;
}
return temp;
}
求链表长度
注意函数类型要与函数返回值相同,长度length用的是int类型,那么函数也应该用int类型
//链表长度
int listlength(Linklist* list) {
Linklist* temp = list;
int length = 0;
while (temp->next != NULL) {
temp = temp->next;
++length;
}
return length;
}
打印链表
void print(Linklist* list) {
Linklist* h = list;
while (h->next != NULL) {
h = h->next;
printf("%d ->", h->score);
}
printf("NULL\n");
}
下面是主函数
int main()
{
int n, f; //n为节点,f为功能
Linklist* list; //声明list指针为空指针
printf("create node number:");
scanf_s("%d", &n);
list = create(n);
printf("_______________________________\ninside node:\n\n");
print(list);
n = 0;
int flag = 1;
while (flag == 1) {
printf("_______________________________\nwhat can i do?:\n1.change\n2.delet\n3.insert\n4.getnode\n5.destroy\n6.clear\n7.create\n8.listlength\n0.out\n_______________________________\n");
scanf_s("%d", &f);
if (1 == f) {
printf("change node:");
scanf_s("%d", &n);
change(list, n);
printf("_______________________________\ninside node:\n\n");
print(list);
}
else if (2 == f) {
printf("delet node:");
scanf_s("%d", &n);
delet(list, n);
printf("_______________________________\ninside node:\n\n");
print(list);
}
else if (3 == f) {
printf("insert node:");
scanf_s("%d", &n);
insert(list, n);
printf("_______________________________\ninside node:\n\n");
print(list);
}
else if (4 == f) {
printf("getnode:");
scanf_s("%d", &n);
Linklist* temp;
temp = getnode(list, n);
printf("%d\n", *temp);
}
else if (5 == f) {
destroy(list);
printf("now list is destroy\n");
flag = 0;
}
else if (6 == f) {
clear(list);
printf("now list is clear\n");
}
else if (7 == f) {
Linklist* list; //声明list指针为空指针
printf("create node number:");
scanf_s("%d", &n);
list = create(n);
printf("_______________________________\ninside node:\n\n");
print(list);
}
else if (8 == f) {
int temp = listlength(list);
printf("length:%d\n",temp);
}
else if (0 == f) {
printf("bye!");
flag = 0;
}
}
}