一种数据存放的思想,数据结构。方便:增删改查
我们所熟知的数组,他的地址是连续的,一个接着一个,那么如果我想要删除或者修改其中的某一个元素时,那么这个时候数组就及其的不方便,因为的地址是连续的。
那么如果我们在这个时候引入链表,他的每个元素存放着下一个元素的地址,这样删除修改元素时只需修改下一个元素地址走向
#include
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('\n');//单引号
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;
}
#include
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('\n');//单引号
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;
}
#include
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('\n');//单引号
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\n",a);
int b = searchlink(&t1,0);
if(b){
printf("you found it\n");
}else{
printf("you don't found it\n");
}
return 0;
}
1 2 3 4 这是一个链表,一个链一个,如果我们想在3的后面插入一个100,一共分三步
#include
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('\n');//单引号
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 \n");
insertlink(&t1,1,&New);
prinftlink(&t1);
}
难点在于链表的头如何插入?如果在链表头插入新元素,这个时候链表的头就发生了改变
#include
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 \n");
insertlinkfrombehind(head,1,&New);
prinftlink(head);
struct Test New2 ={200,NULL};
head = insertlinkfromforward(head,1,&New2);
puts("after insert forword is \n");
prinftlink(head);
}
假设目前五个数 1 2 3 4 5 想要删除某个节点
情况一:如果是头节点呢?删除之后头节点会变
情况二:不是头节点,if(p->next->data == data) p->next = p->next->next
#include
#include
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('\n');
head = deleteNote(head,2);
prinftlink(head);
}
直接在查找的基础上改不就行了吗?
#include
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('\n');//单引号
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\n",a);
int b = searchlink(&t1,0);
if(b){
printf("you found it\n");
}else{
printf("you don't found it\n");
}
return 0;
}
#include
#include
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:\n");
scanf("%d,",&(New->data));
if(New ->data ==0){
printf("0 quit\n");
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
#include
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:\n");
scanf("%d,",&(New->data));
if(New ->data ==0){
printf("0 quit\n");
return head;
}
head = insertFormHead(head,New);
}
}
int main()
{
struct Test *head = NULL;
head = insertFormHead(head);
printflink(head);
return 0;
}
#include
#include
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:\n");
scanf("%d,",&(New->data));
if(New ->data ==0){
printf("0 quit\n");
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:\n");
scanf("%d,",&(New->data));
if(New ->data ==0){
printf("0 quit\n");
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;
}
至此,单向链表完结啦!! “请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信生活中总有美好值得我们全力以赴,哪怕粉身碎骨!”