C语言数据结构-----链表类型详解及链表练习题

0.前言

之前我讲解了循序表以及单链表,接下来我会在介绍几个不同的链表,并举例相关习题使大家能够更加深入的理解。
前期内容如下:
链接: 顺序表(动态顺序表增删查改的代码实现)
链接: 单链表(无头单向不循环)增删查改的代码实现
链接: 双向链表增删查改的代码实现


1.带哨兵位头节点的链表

在这里插入图片描述
哨兵位头节点有什么作用?
当一个链表为空的时候,如果没有哨兵位,那么是直接指向NULL的。如果有哨兵位,那么先指向head,再指向NULL。如图所示:

在这里插入图片描述

2.双向链表

在这里插入图片描述

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都
是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了。

在这里插入图片描述
除此之外还有带环链表,下面的习题中我会进行讲解。
还有双向链表的增删查改,后续我也会放在我的gitee中供大家学习。

3.链表习题一,反转链表(不带哨兵位)

在这里插入图片描述

思路: 在这里插入图片描述

struct ListNode* reverseList(struct ListNode* head) 
{
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode* pre,*mid,*last;
    pre=NULL;
    mid=head;
    last=head->next;

    while(mid!=NULL)
    {
        mid->next=pre;
        pre=mid;
        mid=last;
        if(last!=NULL)
        last=last->next;
    }
    return pre;
}

4.链表习题二,链表分割(带哨兵位)

在这里插入图片描述
这个题是什么意思呢?
在这里插入图片描述

思路:在这里插入图片描述

但是如果是极端情况,比如val的值为1,tail1的next指向head2,就需要单独处理,不仅仅需要处理tail1还需要处理head1,因为默认情况下两个链表都不为空,返回head1;如果所有值都比val小,没有比它大的,那么第二个链表就会为空。
尾插后还需要一定的链接,这就是这题的复杂所在,那么头节点可以帮我们省去一定的麻烦。

如果这里我们使用带哨兵位的头节点,那么就会省去很多麻烦。使用了哨兵位,那么我们的head1和head2始终不会为空。如图所示:
在这里插入图片描述

ListNode* partition(ListNode* pHead, int x) 
    {
        struct ListNode* head1,*tail1,*head2,*tail2;
        head1=tail1=(struct ListNode*)malloc(sizeof(struct ListNode));//
        head2=tail2=(struct ListNode*)malloc(sizeof(struct ListNode));//malloc出哨兵位的头节点
        struct ListNode* cur=pHead;//原链表的头

        while(cur!=NULL)
        {   
            if(cur->val<x)//小于x的尾插到链表1
            {
                tail1->next=cur;
                tail1=tail1->next;
            }
            else //大于等于x的尾插到链表2
            {
                tail2->next=cur;
                tail2=tail2->next;
            }
            cur=cur->next;//下一个循环
        }
        tail1->next=head2->next;//体现了哨兵位的方便
        tail2->next=NULL;
        pHead=head1->next;
        free(head1);
        free(head2);//释放malloc的空间
        return pHead;     
    }

5.链表习题三,带环链表(多个题目环环相扣)

5.1 判断是否有环?

在这里插入图片描述

思路:
在这里插入图片描述

bool hasCycle(struct ListNode *head) 
{
        struct ListNode* fast=head,*slow=head;
        while((fast!=NULL)&&((fast->next)!=NULL))
        {
            fast=fast->next->next;
            slow=slow->next;
            if(slow==fast)
            {
            return true;
            }
        }
         return false;
}

5.2 判断入环节点的位置

在这里插入图片描述

思路:
在这里插入图片描述

struct ListNode *detectCycle(struct ListNode *head)
{
    struct ListNode* slow,* fast;
    slow=fast=head;
    while((fast!=NULL)&&((fast->next)!=NULL))
    {
        //慢指针走一步,快指针走两步
        slow=slow->next;
        fast=fast->next->next;
        
        if (slow==fast)
        {
            struct ListNode* meet=fast;//快慢指针相遇的话,让meet为相遇点
            while(head!=meet)
            {
                head=head->next;
                meet=meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

5.3 附加问题(如果慢指针一次一步,快指针一次三步,会相遇嘛?)

在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Chris·Bosh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值