【C语言】数据结构单向链表

链表的学习

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('\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;
}

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('\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;
}

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('\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;
}

5.链表的插入

在节点的后方插入新数据

1 2 3 4 这是一个链表,一个链一个,如果我们想在3的后面插入一个100,一共分三步

  1. 找到3这个数
  2. 让新节点的指针指到4
  3. 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('\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 <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  \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);
}

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('\n');
	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('\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;
}

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:\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 <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:\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 <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:\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;
}

至此,单向链表完结啦!! “请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信生活中总有美好值得我们全力以赴,哪怕粉身碎骨!”

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言中,使用malloc函数可以动态地分配内存空间。下面是一个示例,演示了如何使用malloc函数来分配空间并创建一个单向链表: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct Node { int data; struct Node* next; } Node; // 创建链表节点 Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); if (newNode == NULL) { printf("内存分配失败\n"); return NULL; } newNode->data = data; newNode->next = NULL; return newNode; } // 初始化链表 Node* initList() { Node* head = createNode(0); // 创建头节点 if (head == NULL) { return NULL; } return head; } // 在链表末尾插入节点 void insertNode(Node* head, int data) { Node* newNode = createNode(data); if (newNode == NULL) { return; } Node* temp = head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } // 打印链表 void printList(Node* head) { Node* temp = head->next; // 跳过头节点 while (temp != NULL) { printf("%d ", temp->data); temp = temp->next; } printf("\n"); } // 释放链表内存 void freeList(Node* head) { Node* temp = head; while (temp != NULL) { Node* nextNode = temp->next; free(temp); temp = nextNode; } } int main() { Node* head = initList(); // 初始化链表 if (head == NULL) { return 0; } insertNode(head, 1); // 在链表末尾插入节点 insertNode(head, 2); insertNode(head, 3); printList(head); // 打印链表 freeList(head); // 释放链表内存 return 0; } ``` 这段代码演示了如何使用malloc函数来分配空间并创建一个单向链表。首先,我们定义了一个链表节点结构体,包含数据和指向下一个节点的指针。然后,我们实现了创建节点、初始化链表、插入节点、打印链表和释放链表内存的函数。在主函数中,我们初始化链表,插入节点,打印链表,最后释放链表内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘猫.exe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值