单链表的创建、删除、反转、插入、排序操作

单链表的创建、删除、反转、插入、排序操作

1.1 链表引言

​ 在初学链表时很多人会问,什么是链表,链表怎么实现,原理是什么?的确带着问题学习会让你变得更快,链表可以简单理解为老师领着幼儿园小朋友过马路,他们手拉手牵着一起,老师在最前面领着后面的小朋友,老师就是这个领头人(链表的头节点),每一个小朋友可以看做一个节点。

在这里插入图片描述

1.2 单链表节点的数据结构

​ 单链表的节点数据根据自己的需要自行设置,但是数据中必然存在一个指针,而且指针类型为本数据类型,本文为了展示出其相关操作的原理,因此节点的数据定义相对简单。

/*链表的节点结构定义*/
typedef struct list_node {
    int data;
    struct list_node *next;
}list_node;

1.3 创建链表

​ 创建链表需要自定义一个函数,指定链表头,应该创建几个节点,每个节点的数据自行输入所以进行如下定义。使用whlie语句进行创建几个节点的判断,并且对每一个节点进行动态分配空间,通过scanf输入数据。当知道有几个小朋友需要连接老师(头节点)时就很容易知道,老师的下一个牵手的应该是一个小朋友,而最后一个小朋友没有东西牵着,所以为NULL。

int creat_list(list_node *head,int n)
{
    if(head!=NULL&&n>0)
    {
        list_node *p=head;
        int input_data;
        while(n>0)
        {
            p->next=(list_node *)malloc(sizeof (list_node));
            printf("please input data:\n");
            scanf("%d",&input_data);
            p->next->data=input_data;
            p=p->next;
            n--;
            head->data++;
        }
        p->next=NULL;//链表的尾部节点下个指向为空,理解最后一个小朋友没东西牵着
        return 0;
    }
    else
    {
        printf("输入创建链表参数出错:\n");
        return -1;
    }
}

1.4 打印整个链表

​ 打印链表实现相对简单,相当于老师牵着小朋友,让每个小朋友进行报数,当到最后一个小朋友时牵着为空气,报数完毕,所以判断条件就是当下一个指针指向为空的时候停止遍历链表。

/*打印整个链表*/
void print_list(list_node *head)
{
    if(head!=NULL)
    {
        printf("sum node %d\n",head->data);
        list_node *p=head->next;
        while(p!=NULL)
        {
            printf("~~~~~~~~~~~%d\n",p->data);
            p=p->next;
        }
    }
}

1.5 链表插入数据

​ 链表插入的函数,指定要插入的链表的头节点,插入的位置,需要插入的数据。插入的原理如下图:假设在1号和2号之间需要插入一个小朋友,首先应该报数,当一号报数完毕后,我们知道了应该在此插入,然后停下操作,先创建一个节点空间,然后把小朋友(节点数据)放进这个空间,新插入的小朋友应该是一边被一号牵着,另一边牵着2号。

在这里插入图片描述

/*第一个参数指定链表头,第二参数在哪一个位置之后插入值*/
void insert_data(list_node *head,int data,int n)
{
    if(n<0||head->data<n||head==NULL)
    {
        printf("插入参数出错\n");
    }
    else
    {
        list_node *p=head->next;
        list_node *pre=head;
        while(n>0)//此处相当于先报数
        {
            pre=p;
            p=p->next;
            n--;
        }
        list_node *new_node=(list_node *)malloc(sizeof (list_node));
        new_node->data=data;
        new_node->next=p;          //此处对应红色解释图
        pre->next=new_node;
        head->data++;
    }
}

1.6 删除某一个节点

​ 删除某一个节点,也是需要知道链表的表头,和删除第几个节点,原理和插入类似,如下图所示:

在这里插入图片描述

void delete_data(list_node *head,int n)
{
    if(n<=0||head==NULL)
    {
        printf("输入参数错误");
        return;
    }
    else
    {
        list_node *pre=NULL;
        list_node *current=head;
        list_node *next=head->next;
        while(n>0)
        {
            pre=current;
            current=next;
            next=next->next;
            n--;
        }
        pre->next=next;
        free(current);
    }
}

1.7 删除整个链表

​ 删除整个链表可不是直接free表头就行了,要一个个遍历整个链表,然后记录前一个指针的位置进行一个一个free,原理和删除一个类似,这里直接上代码。

/*对整个链表进行删除*/
void delete_list(list_node *head)
{
    if(head!=NULL)
    {
        list_node *pre=NULL;
        list_node *current=head;
        list_node *next=head->next;
        while(current!=NULL)
        {
            pre=current;
            current=next;
            next=next->next;
            free(pre);
        }
        free(current);
    }
    else
    {
        printf("链表已经为空\n");
    }
}

1.8 链表的反转

​ 这个相对来说难一点,但是理解原理之后还是很容易的,有点类似于排序,但是有点区别。

反转一步一步的过程应该是这样,也有其他方法,自己查一下。

head->1->2->3->4->5 --------------------------------------原始链表

head->2->1->3->4->5 ---------------------------------------第一步

head->3->2->1->4->5 ---------------------------------------第二步

head->4->3->2->1->5 ---------------------------------------第三步

head->5->4->3->2->1 ---------------------------------------第四步

也就是相当于,每次把遍历到的当前数据提到最前面。

在这里插入图片描述著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/*链表的反转*/
void reversal_list(list_node *head)
{
    if(head!=NULL)
    {
        list_node *current=head->next;
        list_node *next=current->next;
        while(next!=NULL)
        {
            current->next=next->next;
            next->next=head->next;
            head->next=next;

            next=current->next;
        }
    }
    else
    {
        printf("链表为空\n");
    }
}

1.9 链表的排序

​ 此次链表的排序使用的是选择排序,相对简单,使用冒泡等也能实现,简单讲一下冒泡的原理:

head->1->2->3->4 --------------------------------------原始链表

head->4->2->3->1 ---------------------------------------第一步

head->4->3->2->1 ---------------------------------------第二步

就是进行先让第一个数和之后的每一个数比较,只要遇到比他大的就和第一个位置交换数据,然后第一个位置就是最大的数据,之后让第二位与之后的每一个数据比较只要比他大的数就交换位置,…一直这么结束,排序完成。

/*使用选择排序*/
void list_sort(list_node *head)
{
    /*头节点的data用来存储总共有多少节点*/
    if(head==NULL)
        return;
    int i=0;
    int k=0;
    list_node *p=head->next;
    for(i=0;i<head->data-1;i++)
    {
        list_node *s=p->next;
        for(k=i+1;k<head->data;k++)
        {
            if((s->data)<(p->data))
            {
                int tem=p->data;
                p->data=s->data;
                s->data=tem;
            }
            s=s->next;
        }
        p=p->next;
    }
}

                 **持续更新链表的循环链表、双向链表操作**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值