前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【线性表】—带头哨兵卫单链表的应用

【线性表】—带头哨兵卫单链表的应用

作者头像
诺诺的包包
发布2023-02-20 10:54:31
1910
发布2023-02-20 10:54:31
举报
文章被收录于专栏:个人笔记总结

目录

前言

我们之前学过了无头单向非循环链表的实现,但是我们发现,该链表在尾插的时候有一点不好,就是第一次尾插时,会改变头节点,所以我们在上篇文章实现时传的是二级指针。

而本次所讲哨兵卫单链表在尾插时则不用改变头节点。所谓哨兵卫,其实就是带了一个头节点,该节点不作为用来存储数据。如下:

在这里插入图片描述
在这里插入图片描述

接下来我们通过具体题目来感受该结构带来的好处。

实战练习

链表分割

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

思路:假如这道题不是一个链表题,而是一个数组题,我相信大家很多人都会想到这么一个办法,开辟两个数组,然后对原数组进行遍历,<x的放在arr1中,剩下的放在arr2中,然后再将arr2合并到arr1中。 对于链表题我们也可以这么来搞,用两个链表分别链接<x以及其余的,最后再合并两个链表。不过这里我们用哨兵卫单链表实现的话,就不需要考虑到链表是否为空的情况。如下:

在这里插入图片描述
在这里插入图片描述

代码实现:

代码语言:javascript
复制
class Partition {
  public:
    ListNode* partition(ListNode* pHead, int x) {
        //哨兵卫单链表,两个单链表分别存放<x和>x,最后合并
        ListNode* newnode1 = (ListNode*)malloc(sizeof(ListNode));
        ListNode* newnode2 = (ListNode*)malloc(sizeof(ListNode));
        ListNode* tail1 = newnode1;
        ListNode* tail2 = newnode2;
        while (pHead) {
            //<x的放在newnode1链表
            if (pHead->val < x) {
                tail1->next = pHead;
                tail1 = tail1->next;
            }
            //>=x的放在newnode2链表 
            else {
                tail2->next = pHead;
                tail2 = tail2->next;
            }
            pHead = pHead->next;

        }
        //链接两个链表
        tail1->next=newnode2->next;
        tail2->next=NULL;//一定记得置空!否则又可能出现死循环
        struct ListNode*phead=newnode1->next;//保存下一个节点
        //释放
        free(newnode1);
        free(newnode2);
        return phead;
    }
};

这里我们就不需要考虑链表是否为空的情况,会省很多事,因此对于一些单链表的题目,只要涉及到尾插问题,建议使用带头哨兵卫单链表。并且再次强调,一定要多画图!

合并两个有序链表

在这里插入图片描述
在这里插入图片描述

这道题,把它想象成一个普通的题,我们应该都会做,即双指针遍历,然后取小尾插。这里需要注意的是,当一方遍历完,另一方没完时,直接将没完的那一方插入即可。这里涉及到尾插,为了不用考虑空表情况下的尾插,我们依然采用哨兵卫单链表。如下:

在这里插入图片描述
在这里插入图片描述

代码实现:

代码语言:javascript
复制
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    //开辟一个新节点
    struct ListNode*newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
    newnode->next=NULL;
    struct ListNode*tail=newnode;
    while(list1 && list2)
    {
        //取小尾插
        if(list1->val < list2->val)
        {
            tail->next=list1;
            tail=tail->next;
            list1=list1->next;
        }
        else
        {
            tail->next=list2;
            tail=tail->next;
            list2=list2->next;
        }
    }
    //list2为空
    if(list1)
    {
        tail->next=list1;
    }
    //list1为空
    if(list2)
    {  
        tail->next=list2;
    }
    //保存头节点的下一个节点
    struct ListNode*newhead=newnode->next;
    //释放
    free(newnode);
    return newhead;
}

总结

** 对于需要进行尾插的链表,我们采用带头哨兵卫单链表用来实现尾插,会省事很多,不用考虑空表的存在,不过要注意的是,因为这个哨兵卫节点是我们malloc出来的,所以最后一定记得释放,并且哨兵卫节点的下一个节点才是用来存储有效数据的,另!一定要多画图! **

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 前言
  • 实战练习
    • 链表分割
      • 合并两个有序链表
      • 总结
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档