链表的学习
文章目录
- 链表的学习
-
- 1.什么是链表
- 2.静态创建链表
-
- 1.链表与数组的区别及实现
- 3.链表的遍历
- 4.链表的查找
-
- 统计链表节点个数及链表查找
- 5.链表的插入
-
- 在节点的后方插入新数据
- 在节点的前方插入
- 6.链表的删除
- 7.链表的修改
- 8.动态创建链表
-
- 头插法
- 尾插法
1.什么是链表
一种数据存放的思想,数据结构。方便:增删改查
我们所熟知的数组,他的地址是连续的,一个接着一个,那么如果我想要删除或者修改其中的某一个元素时,那么这个时候数组就及其的不方便,因为的地址是连续的。
那么如果我们在这个时候引入链表,他的每个元素存放着下一个元素的地址,这样删除修改元素时只需修改下一个元素地址走向
2.静态创建链表
1.链表与数组的区别及实现
#include <stdio.h> struct Test{ int data; struct Test *next; };//分号不能丢 int main() { int array[]={2,5,9}; for(int i =0;i<sizeof(array)/sizeof(array[0]);i++){ printf("%d ",array[i]); } putchar(' ');//单引号 struct Test t1 ={5,NULL}; struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; t1.next = &t2;//用.运算符给结构体指针赋值 t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 //链表思想,一个链一个 printf("%d %d %d",t1.data,t1.next->data,t1.next->next->data); return 0; }
3.链表的遍历
#include <stdio.h> struct Test{ int data; struct Test *next; };//分号不能丢 void prinftlink(struct Test *head) { struct Test *point; point = head; //我们知道链表的第一个指针存放下一个结构体的地址,第二个存放第三个,而第三个,也就是最后一个他的指针是空的,即NULL //所以我们可以利用这一特性来写循环 /********************************* while(1){ if(point != NULL){ printf("%d ",point->data); point = point ->next; }else{ break;//跳出while(1)死循环 } **********************************/ while(point != NULL){ printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } int main() { int array[]={2,5,9}; for(int i =0;i<sizeof(array)/sizeof(array[0]);i++){ printf("%d ",array[i]); } putchar(' ');//单引号 struct Test t1 ={5,NULL}; struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; struct Test t4 ={4,NULL}; t1.next = &t2;//用.运算符给结构体指针赋值 t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 t3.next = &t4; //数越多,越傻瓜 // printf("%d %d %d",t1.data,t1.next->data,t1.next->next->data); prinftlink(&t1);//这个我们只需要把结构体的头地址放入即可遍历出来 return 0; }
4.链表的查找
统计链表节点个数及链表查找
#include <stdio.h> struct Test{ int data; struct Test *next; };//分号不能丢 void prinftlink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } int getTotalNodeNum(struct Test *head)//查找链表节点个数 { int cnt = 0; while(head != NULL) { cnt++; head = head ->next;//指针偏移,指向下一个结构体指针 } return cnt; } int searchlink(struct Test *head,int data)//查找链表中是否有这个元素 { while(head != NULL) { if(head ->data == data){ return 1; } head = head ->next;//指针偏移,指向下一个结构体指针 } return 0; } int main() { int array[]={2,5,9}; for(int i =0;i<sizeof(array)/sizeof(array[0]);i++){ printf("%d ",array[i]); } putchar(' ');//单引号 struct Test t1 ={5,NULL}; struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; struct Test t4 ={4,NULL}; t1.next = &t2;//用.运算符给结构体指针赋值 t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 t3.next = &t4; prinftlink(&t1);//这个我们只需要把结构体的头地址放入即可遍历出来 int a = getTotalNodeNum(&t1); printf("total num is %d ",a); int b = searchlink(&t1,0); if(b){ printf("you found it "); }else{ printf("you don't found it "); } return 0; }
5.链表的插入
在节点的后方插入新数据
1 2 3 4 这是一个链表,一个链一个,如果我们想在3的后面插入一个100,一共分三步
- 找到3这个数
- 让新节点的指针指到4
- 3的指针指到新节点
#include <stdio.h> struct Test{ int data; struct Test *next; };//分号不能丢 void prinftlink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } int insertlink(struct Test *head,int data,struct Test *New)//在链表中插入新元素 { struct Test *p = head; while(p != NULL) { if(p ->data == data){ New ->next = p->next; p ->next = New; return 1; } p = p ->next;//指针偏移,指向下一个结构体指针 } return 0; } int main() { int array[]={2,5,9}; for(int i =0;i<sizeof(array)/sizeof(array[0]);i++){ printf("%d ",array[i]); } putchar(' ');//单引号 struct Test t1 ={5,NULL}; struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; struct Test t4 ={4,NULL}; t1.next = &t2;//用.运算符给结构体指针赋值 t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 t3.next = &t4; struct Test New ={100,NULL}; prinftlink(&t1);//这个我们只需要把结构体的头地址放入即可遍历出来 puts("after insert behind is "); insertlink(&t1,1,&New); prinftlink(&t1); }
在节点的前方插入
难点在于链表的头如何插入?如果在链表头插入新元素,这个时候链表的头就发生了改变
#include <stdio.h> struct Test{ int data; struct Test *next; };//分号不能丢 void prinftlink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } int insertlinkfrombehind(struct Test *head,int data,struct Test *New)//在链表中插入新元素 { struct Test *p = head; while(p != NULL) { if(p ->data == data){ New ->next = p->next; p ->next = New; return 1; } p = p ->next;//指针偏移,指向下一个结构体指针 } return 0; } struct Test *insertlinkfromforward(struct Test *head,int data,struct Test *New) { struct Test *p = head; //如果是头节点的话,直接插入,把New返回回去 if(p ->data == data){ New ->next = head; return New; } //如果不是头节点,那我就可以向下遍历了 while(p->next != NULL) { if(p->next->data == data)//这是变化的地方 { New->next =p->next; p ->next = New; return head;//换完直接返回退出,不用向下走了 } p = p ->next; } return head; } int main() { struct Test *head = NULL; struct Test t1 ={5,NULL}; struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; struct Test t4 ={4,NULL}; t1.next = &t2;//用.运算符给结构体指针赋值 t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 t3.next = &t4; head = &t1; struct Test New ={100,NULL}; prinftlink(head);//这个我们只需要把结构体的头地址放入即可遍历出来 puts("after insert behind is "); insertlinkfrombehind(head,1,&New); prinftlink(head); struct Test New2 ={200,NULL}; head = insertlinkfromforward(head,1,&New2); puts("after insert forword is "); prinftlink(head); }
6.链表的删除
假设目前五个数 1 2 3 4 5 想要删除某个节点
情况一:如果是头节点呢?删除之后头节点会变
情况二:不是头节点,if(p->next->data == data) p->next = p->next->next
#include <stdio.h> #include <stdlib.h> struct Test{ int data; struct Test *next; };//分号不能丢 void prinftlink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } struct Test* deleteNote(struct Test *head,int data) { struct Test *p = head; if(p->data == data) { head = head->next; free(p); } while(p->next != NULL) { if(p->next->data == data) { p->next = p->next->next; return head; } p = p->next; } return head; } int main() { struct Test *head = NULL; //struct Test t1 ={5,NULL}; struct Test *p =(struct Test*)malloc(sizeof(struct Test));//动态创建,继续用以前的静态创建会报错 struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; struct Test t4 ={4,NULL}; // t1.next = &t2;//用.运算符给结构体指针赋值 p->data = 1; p->next = &t2; t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 t3.next = &t4; // head = &t1; head = p; prinftlink(head);//这个我们只需要把结构体的头地址放入即可遍历出来 putchar(' '); head = deleteNote(head,2); prinftlink(head); }
7.链表的修改
直接在查找的基础上改不就行了吗?
#include <stdio.h> struct Test{ int data; struct Test *next; };//分号不能丢 void prinftlink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } int getTotalNodeNum(struct Test *head)//查找链表节点个数 { int cnt = 0; while(head != NULL) { cnt++; head = head ->next;//指针偏移,指向下一个结构体指针 } return cnt; } int searchlink(struct Test *head,int data,int newdata)//查找链表中是否有这个元素 { while(head != NULL) { if(head ->data == data){ head ->data = newdata; return 1; } head = head ->next;//指针偏移,指向下一个结构体指针 } return 0; } int main() { int array[]={2,5,9}; for(int i =0;i<sizeof(array)/sizeof(array[0]);i++){ printf("%d ",array[i]); } putchar(' ');//单引号 struct Test t1 ={5,NULL}; struct Test t2 ={2,NULL}; struct Test t3 ={1,NULL}; struct Test t4 ={4,NULL}; t1.next = &t2;//用.运算符给结构体指针赋值 t2.next = &t3;//t2结构体指针里面存放着t3结构体(属于一个块地址,里面存放着很多变量)的地址 t3.next = &t4; prinftlink(&t1);//这个我们只需要把结构体的头地址放入即可遍历出来 int a = getTotalNodeNum(&t1); printf("total num is %d ",a); int b = searchlink(&t1,0); if(b){ printf("you found it "); }else{ printf("you don't found it "); } return 0; }
8.动态创建链表
头插法
#include <stdio.h> #include <stdlib.h> struct Test{ int data; struct Test *next; };//分号不能丢 void printflink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } struct Test *insertFormHead(struct Test *head) { struct Test* New; while(1) { New = (struct Test *)malloc(sizeof(struct Test)); printf("input your new node data: "); scanf("%d,",&(New->data)); if(New ->data ==0){ printf("0 quit "); return head; } if(head == NULL){ head = New; }else{ New->next = head; head = New; } } return head; } int main() { struct Test *head = NULL; head = insertFormHead(head); printflink(head); return 0; }
对上优化
#include <stdio.h> #include <stdlib.h> struct Test{ int data; struct Test *next; };//分号不能丢 void printflink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } struct Test *insertFormHead(struct Test *head,struct Test *New) { if(head == NULL){ head = New; }else{ New->next = head; head = New; } return head; } struct Test *creatlink(struct Test *head) { struct Test* New; while(1) { New = (struct Test *)malloc(sizeof(struct Test)); printf("input your new node data: "); scanf("%d,",&(New->data)); if(New ->data ==0){ printf("0 quit "); return head; } head = insertFormHead(head,New); } } int main() { struct Test *head = NULL; head = insertFormHead(head); printflink(head); return 0; }
尾插法
#include <stdio.h> #include <stdlib.h> struct Test{ int data; struct Test *next; };//分号不能丢 void printflink(struct Test *head) { struct Test *point; point = head; while(point != NULL) { printf("%d ",point->data); point = point ->next;//指针偏移,指向下一个结构体指针 } } struct Test *insertFormHead(struct Test *head,struct Test *New) { if(head == NULL){ head = New; }else{ New->next = head; head = New; } return head; } struct Test *creatlink(struct Test *head) { struct Test* New; while(1) { New = (struct Test *)malloc(sizeof(struct Test)); printf("input your new node data: "); scanf("%d,",&(New->data)); if(New ->data ==0){ printf("0 quit "); return head; } head = insertFormHead(head,New); } } struct Test *insertbehind(struct Test *head,struct Test *new) { struct Test *p = head; if(p == NULL){ head = new; return head; } while(p ->next != NULL)//没有到尾巴前一直偏移指针 { p = p->next; } p->next = new; return head; } struct Test *creatlink2(struct Test *head) { struct Test* New; while(1) { New = (struct Test *)malloc(sizeof(struct Test)); printf("input your new node data: "); scanf("%d,",&(New->data)); if(New ->data ==0){ printf("0 quit "); return head; } head = insertbehind(head,New); } } int main() { struct Test *head = NULL; head = creatlink2(head); printflink(head); //头插法 struct Test t1 ={1000,NULL}; head = insertFormHead(head,&t1); printflink(head); //尾插法 struct Test t2 ={2000,NULL}; head = insertbehind(head,&t2); printflink(head); return 0; }
至此,单向链表完结啦!! “请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信生活中总有美好值得我们全力以赴,哪怕粉身碎骨!”