数据结构-链表

1、链表的概念

链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构
链表由一些列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成(malloc),每个节点包括两部分:
1、存储数据元素的数据域
2、存储下一个节点地址的指针域

2、链表节点

在这里插入图片描述

3、链表的定义

typedef struct stu
{
	//数据域
	int num;
	char name[32];
	float score;

	//指针域,next保存下一个节点的地址编号
	struct stu *next;
}

例如

#include <stdio.h>  
  
typedef struct stu  
{  
    //数据域  
    int num;  
    char name[32];  
    float score;  
  
    //指针域  
    //next保存下一个节点的地址 编号  
    struct stu *next;  
}STU;  
void test01()  
{  
    STU data1={100,"lucy",89.1,NULL};  
    STU data2={101,"lucy1",89.1,NULL};  
    STU data3={102,"lucy2",89.1,NULL};  
    STU data4={103,"lucy3",89.1,NULL};  
  
    //链表头  
    STU *head = &data1;  
    data1.next = &data2;  
    data2.next = &data3;  
    data3.next = &data4;  
  
    //遍历  
    STU *pb = head;  
    while(pb != NULL)  
    {  
        printf("%d %s %f\n", pb->num, pb->name,pb->score);  
        //去往下一个节点  
        pb = pb->next;  
    }  
  
}  
int main(int argc, char const *argv[])  
{  
    test01();  
    return 0;  
}  

对链表的操作包括 增、删、改、查;链表的功能十分强大,在复杂的工程中会有双线链表,循环链表;

4、链表的插入操作

1、头插法

就是字面意思,每一个新插入的节点都将成为链表的新头部。

在这里插入图片描述

STU* insert_link(STU *head, STU tmp)  
{  
    //1、为插入的节点 申请 堆区空间  
    STU *pi = (STU *)calloc(1,sizeof(STU));  
    //2、将tmp的数据 赋值到 *pi中  
    *pi = tmp;  
    //将pi->next赋值为NULL  
    pi->next = NULL;  
  
    //3、判断链表是否为NULL  
    if(head == NULL)//链表不存在  
    {  
        head = pi;  
        //return head;  
    }  
    else//链表存在  
    {  
        //让pi->next指向旧的head节点  
        pi->next = head;  
  
        //更新头节点 信息  
        head = pi;  
        //return head;  
    }  
  
    return head;  
}  
2、尾插法

每一个新节点都将成为链表的尾部。

在这里插入图片描述

//尾部插入  
STU* insert_link(STU *head, STU tmp)  
{  
    //1、为带插入的节点 申请空间  
    STU *pi = (STU *)calloc(1,sizeof(STU));  
    //2、将tmp的数据 赋值给*pi  
    *pi = tmp;  
    pi->next = NULL;  
  
    //3、判断链表 是否存在  
    if(head == NULL)//不存在  
    {  
        head = pi;  
        //return head;  
    }  
    else//存在  
    {  
        //寻找尾节点  
        STU *pb = head;  
        while(pb->next != NULL)  
        {  
            pb = pb->next;  
        }  
  
        //将尾节点的 指针域next 指向新的pi节点  
        pb->next = pi;  
        //return head;  
    }  
    return head;  
}
3、链表的有序插入

在这里插入图片描述

//链表的有序插入  
STU* insert_link(STU *head, STU tmp)  
{  
    //1、为待插入的节点 申请空间  
    STU *pi = (STU *)calloc(1,sizeof(STU));  
    //2、将tmp的数据 赋值给*pi  
    *pi = tmp;  
    pi->next = NULL;  
  
    //判断链表 是否为空  
    if(head == NULL)//为NULL  
    {  
        head = pi;  
        return head;  
    }  
    else//不为空  
    {     
        //逐个节点寻找插入点的位置  
        STU *pf = head, *pb = head;  
        //pb->num < pi->num 按照num从小-->大排  
        //pb->next != NULL 防止链表 查询越界  
        while((pb->num < pi->num) && (pb->next != NULL))  
        {  
            //pf记录pb移动之前的位置  
            pf = pb;  
            //pb往下一个节点移动  
            pb = pb->next;  
        }  
  
        //判断插入点的位置(前  中  尾)  
        if(pb->num >= pi->num)//前 中  
        {  
            if(pb == head)//头部前 插入  
            {  
                pi->next = head;//保存旧链表的头地址  
                head = pi;//跟新新链表头地址  
            }  
            else//中部 插入  
            {  
                pf->next = pi;  
                pi->next = pb;  
            }  
        }  
        else if(pb->next == NULL)//尾部  
        {  
            pb->next = pi;  
        }  
    }  
      
    return head;//重要  
}  

4、链表的遍历

在这里插入图片描述

void print_link(const STU *head)  
{  
    //1、判断链表 是否存在  
    if(head == NULL)//不存在  
    {  
        printf("链表不存在\n");  
        return;  
    }  
    else//存在  
    {  
        const STU *pb = head;  
        while(pb != NULL)  
        {  
            printf("num=%d, name=%s, score=%f\n", pb->num, pb->name, pb->score);  
            pb = pb->next;  
        }  
    }  
}  

5、链表的查找

在这里插入图片描述

STU* find_link(STU *head, char *name)  
{  
    //1、判断链表是否存在  
    if(head == NULL)  
    {  
        printf("链表不存在\n");  
        return NULL;  
    }  
    else//链表存在  
    {  
        //逐个节点查询  
        STU *pb = head;  
        while((strcmp(pb->name, name) != 0) && (pb->next != NULL))  
        {  
            pb = pb->next;  
        }  
  
        //判断越界 还是找到相应的节点  
        if(strcmp(pb->name, name) == 0)//找到  
        {  
            return pb;  
        }  
        else if(pb->next == NULL)//未找到  
        {  
            printf("未找到姓名为%s的节点信息\n", name);  
            return NULL;  
        }  
    }  
    return NULL;  
}  

6、删除链表指定节点

在这里插入图片描述

STU* delete_link(STU *head,float score)  
{     
    //判断链表是否存在  
    if(head == NULL)//不存在  
    {  
        printf("链表不存在\n");  
        return head;  
    }  
    else//存在  
    {  
        //逐个节点查询删除点  
        STU *pf = head, *pb = head;  
        while((pb->score != score) && (pb->next != NULL))  
        {  
            pf = pb;  
            pb = pb->next;  
        }  
  
        if(pb->score == score)//找到删除点  
        {  
            if(pb ==head)//删除头节点  
            {  
                head = head->next;  
            }  
            else//删除中、尾节点  
            {  
                pf->next = pb->next;  
            }  
  
            //释放要删除的节点  
            free(pb);  
            printf("节点删除成功\n");  
            return head;  
        }  
        else//未找到删除点  
        {  
            printf("未找到删除点\n");  
            return head;//重要  
        }  
    }  
      
    return head;  
}  

7、释放整个链表

while (pb! =NULL)
{
	//先记录下一个节点的位置head = head->next;
	//释放pb的节点free(pb);
	//更新pb的位置pb = head;
}
STU *free_link(STU *head)  
{  
    //判断链表 是否存在  
    if(head == NULL)  
    {  
        printf("链表不存在\n");  
        return head;  
    }  
    else//存在  
    {  
        STU *pb = head;  
        //逐个节点释放  
        while(pb != NULL)  
        {  
            //head记录下一个节点的位置  
            head = head->next;  
            //释放pb  
            free(pb);  
            //更新pb的位置  
            pb = head;  
        }  
        return head;  
    }  
    return head;  
}  

8、链表的逆序

STU* reverse_link(STU *head)  
{  
    //判断链表是否存在  
    if(head == NULL)  
    {  
        printf("链表不存在\n");  
        return head;  
    }  
    else  
    {  
        STU *pb = NULL, *pr = NULL;  
        //pb的初始值  
        pb = head->next;  
        //将head->next置NULL  
        head->next = NULL;  
  
        //逐个节点逆置  
        while(pb != NULL)  
        {  
            //使用pr记录pb->next;  
            pr = pb->next;  
            //更改pb->next;  
            pb->next = head;  
            //更新head  
            head = pb;  
            //更新pb  
            pb = pr;  
        }  
    }  
      
    return head;  
}

在这里插入图片描述

9、双向链表

双向链表可以更灵活的 进行数据的增删改查,后续在进行详细总结。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值