C语言之链表

在学习C语言的指针和结构体,后面就会学习链表,而对于链表这个词,大家也是没有听说过,因为在大学的C语言书籍里面并没有这个东西,因为这属于数据与结构的内容,所以就没有在C语言书籍里面提过,但肯定是有相关的介绍,并不是很全面。

链表是一种这样的数据结果,其中的各对象按线性顺序排列,数组的线性顺序是由数组下标决定的,然而与数组不同的是,链表的顺序是由各对象的指针决定的,链表的动态集合决定了一种简单而灵活的表示方法。

链表分为单链表和双链表,我们对于单链表和双链表都进行简单的介绍。对于这里的链表更加注重由头节点的介绍,带有头节点的链表使用的更加广泛。

对于单链表就是一个单链接的链表,我们首先要创建一个结构体对象以及头节点。

typedef struct node
{
    int data;
    struct node* next;
}Node;

typedef struct list
{
    Node* frist;
    Node* last;
}List;

对于这个结构体的创建我们只考虑简单的数字插入,对于后面有什么需求,比如字符都是可以在里面继续定义你需要存放的类型。

然后我们需要对这个链表节点进行动态空间分配并进行返回。

/// @brief 创建一个链表节点
/// @param  无
/// @return 返回一个带头结点的链表
List* Creat_List(void)
{
    List* l=(List*)malloc(sizeof(List));
    l->frist=NULL;
    l->last=NULL;
    return l;
}

对于基本操作已经完成的话,我们就要进行链表的插入,对于插入又分为前插和后插,感觉用词乖乖的,前插和后插?可能带有颜色的网页看多了。

/// @brief 进行链表前插
/// @param h 输入的链表
/// @param d 插入的数据
void first_insert_list(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* p=(Node*)malloc(sizeof(Node));
    p->data=d;
    p->next=NULL;
    if(h->frist==NULL)
    {
        h->frist=p;
        h->last=p;
    }
    else
    {
        p->next=h->frist;
        h->frist=p;
    }
}
/// @brief 进行链表后插
/// @param h 输入链表
/// @param d 插入的数据
void last_insert_list(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* p=(Node*)malloc(sizeof(Node));
    p->data=d;
    p->next=NULL;
    if(h->frist==NULL)
    {
        h->frist=p;
        h->last=p;
    }
    else
    {
        h->last->next=p;
        h->last=p;
    }
}

对于按理来说,我们的插入已经完成了,感觉还是不够,我们应该让他更加有序起来,于是一个升序插入的版本诞生了。

/// @brief 对于输入的数据进行链表排序
/// @param h 输入的链表
/// @param d 输入的数据
void supper_insert_list(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* p=(Node*)malloc(sizeof(Node));
    p->data=d;
    p->next=NULL;
    if(h->frist==NULL)
    {
        h->frist=p;
        h->last=p;
    }
    else
    {
        Node* pr=NULL;
        Node* pk=NULL;
        pk=h->frist;
        while (pk)
        {
            if(pk->data>d)
            {
                break;
            }
            pr=pk;
            pk=pk->next;
        }
        if(pk==h->frist)
        {
            p->next=h->frist;
            h->frist=p;
        }else if(pk==NULL)
        {
            pr->next=p;
            h->last=p;
        }else
        {
            pr->next=p;
            p->next=pk;
        }
    }
}

这样的话就能更加地加强了我们对链表的使用程度。但是对于‘增’我们是有了,是不是还少了一个删除操作,我们需要对链表的数据进行删除操作。

/// @brief 删除所有数据相同的节点
/// @param h 输入的链表
/// @param d 需要删除的数据
void delete_list_all(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* pk=NULL;
    Node* pr=NULL;
    Node* ps=h->frist;
    while (1)
    {
        pk=ps;
        while (pk)
        {
            if(pk->data==d)
            {
                break;
            }
            pr=pk;
            pk=pk->next;
        }
        if(pk==NULL)
        {
            break;
        }
        ps=pk->next;
        if(pk==h->frist)
        {
            h->frist=pk->next;
            pk->next=NULL;
        }else if(pk->next==NULL)
        {
            pr->next=NULL;
            h->last=pr;
        }else
        {
            pr->next=pk->next;
            pk->next=NULL;
        }
        free(pk);
    }
    
}

对于单链表我们进行了这么多的操作,是不是需要进行打印起来看看,这样才能知道我们有没有链表创建成功,以及对于链表数据的改变是否成功。

/// @brief 打印链表数据
/// @param l:头节点
void print_list(List* l)
{
    if(l==NULL)
    {
        return ;
    }
    Node* p=l->frist;
    while (p)
    {
        printf("%d ",p->data);
        p=p->next;
    }
    printf("\r\n");
}

对于主函数我只为大家提供一个模板,上面提供的函数并不会全部调用。

int main(void)
{ 
    int d;
    List* l=Creat_List();
    while (1)
    {
        scanf("%d",&d);
        if(!d)
        {
            break;
        }
        supper_insert_list(l,d);
    }
    print_list(l);
    free_all_list(l);
}

然而运行结果证明,以上程序可以使用。

对于双链表又是单链表的进阶版,代表链表里面有两个单链,就是双链。

与单链表极为相识,我们在这里直接附上我们的代码。

typedef struct node
{
    int data;
    struct node* next;
    struct node* prev;
}Node;

typedef struct list
{
    /* data */
    Node* first;
    Node* last;
}List;
/// @brief 创造一个头节点
/// @param  无
/// @return 返回一个已经创建的头节点
List* creat_list(void)
{
    List* p;
    p=malloc(sizeof(List));
    p->first=NULL;
    p->last=NULL;
    return p;
}

/// @brief 尾插法
/// @param h 链表
/// @param d 值
void last_insert_list(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* p=(Node*)malloc(sizeof(Node));
    p->data=d;p->next=NULL,p->prev=NULL;
    if(h->first==NULL)
    {
        h->first=p;
        h->last=p;
    }
    else
    {
        h->last->next=p;
        p->prev=h->last;
        h->last=p;
    }
}

/// @brief 头插法
/// @param h 链表
/// @param d 值
void first_isert_list(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* p=(Node*)malloc(sizeof(List));
    p->data=d;p->next=NULL;p->prev=NULL;
    if(h->first==NULL)
    {
        h->first=p;
        h->last=p;
    }else
    {
        p->next=h->first;
        h->first->prev=p;
        h->first=p;
    }
}
/// @brief 进行双链表的升序插入
/// @param h 需要插序的链表
/// @param d 插入的数据
void supper_isert_list(List* h,int d)
{
    if(h==NULL)
    {
        return ;
    }
    Node* p=(Node*)malloc(sizeof(List));
    p->data=d;p->next=NULL;p->prev=NULL;
    if(h->first==NULL)
    {
        h->first=p;
        h->last=p;
    }else
    {
        Node* pk=h->first;
        while (pk)
        {
            if(pk->data>d)
            {
                break;
            }
            pk=pk->next;
        }
        if(!pk)
        {
            h->last->next=p;
            p->prev=h->last;
            h->last=p;
        }
        else
        {
            if(pk==h->first)
            {
                p->next=h->first;
                h->first->prev=p;
                h->first=p;
            }
            else
            {
                p->next=pk;
                pk->prev->next=p;
                p->prev=pk->prev;
                pk->prev=p;
            }
        }
    }
}
/// @brief 删除单个值
/// @param h 链表
/// @param x 传入需要的值
void delete_x_list(List* h,int x)
{
    Node* p=h->first;
    while (p)
    {
        if(p->data==x)
        {
            break;
        }
        p=p->next;
    }
    if(!p)
    {
        return ;
    }
    else
    {
        if(p==h->first)
        {
            h->first=h->first->next;
            p->next=NULL;
            h->first->prev=NULL;
        }else if(p==h->last)
        {
            h->last=p->prev;
            h->last->next=NULL;
            p->prev=NULL;
        }
        else
        {
            p->next->prev=p->prev;
            p->prev->next=p->next;
            p->next=NULL;
            p->prev=NULL;
        }
        free(p);
    }
}
/// @brief 删除值相同的节点
/// @param h 被执行的链表
/// @param x 一个传入需要被删除的相同值的链表
void delete_all_list(List* h,int x)
{
    Node* p=NULL;
    Node* ps=h->first;
    while (1)
    {
        p=ps;
        while (p)
        {
            if(p->data==x)
            {
                break;
            }
            p=p->next;
        }
        if(!p)
        {
            break;
        }
        ps=p->next;
        if(p==h->first)
        {
            if(h->first==h->last)
            {
                h->first=NULL;
                h->last=NULL;
            }else
            {
                h->first=h->first->next;
                p->next=NULL;
                h->first->prev=NULL;
            }
        }
        else if(p==h->last)
        {
            h->last=p->prev;
            h->last->next=NULL;
            p->prev=NULL;
        }
        else
        {
            p->next->prev=p->prev;
            p->prev->next=p->next;
            p->next=NULL;
            p->prev=NULL;
        }
        free(p);
    }
}
/// @brief 释放链表的空间
/// @param h 被释放的链表
void free_list(List* h)
{
    Node* p=NULL;
    while (h->first)
    {
        printf("ok");
        p=h->first;
        h->first=p->next;
        p->next=NULL;
        p->prev=NULL;
        free(p);
    }
    h->last=NULL;
    free(h);
}
/// @brief 打印正,反序列
/// @param h 被打印的链表
void print_list(List* h)
{
    Node* p=h->first;
    printf("************************");
    printf("\r\n");
    while (p)
    {
        printf("%d ",p->data);
        p=p->next;   
    }
    printf("\r\n");
    p=h->last;
    while (p)
    {
        printf("%d ",p->data);
        p=p->prev;
    }
    printf("\r\n");
    printf("************************");
    printf("\r\n");
}

这样我们就完成了我们的双链表,这样我们链表的基本操作都已经完成了。

在这里我给大家附上一个宝藏网站:

C语言中文网:C语言程序设计门户网站(入门教程、编程软件)

唯一的缺陷就是有部分内容是需要付费的,正所谓人在江湖飘,哪能不挨刀,不付费就想白嫖,是没有免费的午餐吃的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GD32开发者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值