单链表之链表分割

1.问题描述

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

2.问题分析

乍一看毫无思路,不知道题目描述的什么意思,经过分析测试,该题目表达的意思为:(例子)有一链表plist,存放有2->3->6->7->4->2->6->NULL,当x=4时,链表被分割成2->3->2->6->7->4->6->NULL.

对此我们可以采用创建头结点分别存储小于x的值和大于等于x的值,再将两个链表链接在一起,即可实现,如下图所示
在这里插入图片描述
分析完感觉一般般,不符合这道题评判为较难。先别急,先不要急,这才刚刚开始。

3.代码展示

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        //开辟两个头结点
        struct ListNode* littlehead,*littletail,*bighead,*bigtail;
        littlehead=littletail=(struct ListNode*)malloc(sizeof(struct ListNode));
        bighead=bigtail=(ListNode*)malloc(sizeof(struct ListNode));
        littletail->next=NULL;
        bigtail->next=NULL;
        struct ListNode* cur=pHead;
        //循环把比x小的放在littlehead,比x大的放在bighead
        while(cur){
            if(cur->val<x){
                littletail->next=cur;
                littletail=littletail->next;
            }
            else{
                bigtail->next=cur;
                bigtail=bigtail->next;
            }
            cur=cur->next;
        }
        //合并两个链表
        littletail->next=bighead->next;
        pHead=littlehead->next;
        //释放空间
        free(bighead);
        free(littlehead);
        return pHead;
    }

};

上述OJ测试过不了,显示内存超限,申请了两个内存空间能超限?
这是为什么呢?再次思考其他情况。。。

4.问题二次分析(解决问题)

对待这个问题,我们要考虑几个特殊的测试,比如对x而言,有全部都比它大的;也有全部都比它小的;也存在既比他小的,也比他大的,这种情况,我们就需要接着分析了:因为分割之后,要合成一个新链表(判断新链表最后一个节点是否指向空),如果原链表最后一个值比x大,那么比x值大的链表最后一个结点将会指向空;如果原链表最后一个值比x小,那么执行上述代码的时候将会形成一个死循环,如下图所示
在这里插入图片描述

//合并两个链表
        littletail->next=bighead->next;
        bigtail->next=NULL;
        pHead=littlehead->next;

此时,我们只需要在合并链表的时候给它稍微操作一下,让比x值大的链表尾部指向空,就可以解决此问题.

5.附VS下完整版代码,可调式观察,更容易理解

#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>

struct ListNode {
    int val;
    struct ListNode* next;
};

struct ListNode* BuySLnode(int x) {
    struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode));
    if (newnode == NULL) {
        perror("BuySLnode");
        exit(-1);
    }
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
}

void SLTPushBack(struct ListNode** pphead, int x) {
    struct ListNode* newnode = BuySLnode(x);
    if (*pphead == NULL) {
        *pphead = newnode;
    }
    else {
        struct ListNode* tail = *pphead;
        while (tail->next)
        {
            tail = tail->next;
        }
        tail->next = newnode;
    }
}


    struct ListNode* partition(struct ListNode* pHead, int x) {
        //开辟两个头结点
        struct ListNode* littlehead, * littletail, * bighead, * bigtail;
        littlehead = littletail = (struct ListNode*)malloc(sizeof(struct ListNode));
        bighead = bigtail = (struct ListNode*)malloc(sizeof(struct ListNode));
        littletail->next = NULL;
        bigtail->next = NULL;
        struct ListNode* cur = pHead;
        //循环把比x小的放在littlehead,比x大的或相等的放在bighead
        while (cur) {
            if (cur->val < x) {
                littletail->next = cur;
                littletail = littletail->next;
            }
            else {
                bigtail->next = cur;
                bigtail = bigtail->next;
            }
            cur = cur->next;
        }
        //合并两个链表
        littletail->next = bighead->next;
        bigtail->next = NULL;
        pHead = littlehead->next;
        //释放空间
        free(bighead);
        free(littlehead);
        return pHead;
    }

    void SLTPrint(struct ListNode* phead) {
        struct ListNode* cur = phead;
        while (cur != NULL) {
            printf("%d->", cur->val);
            cur = cur->next;
        }
        printf("NULL\n");
    }

int main() {
    struct ListNode *plist=NULL;
    SLTPushBack(&plist,2);
    SLTPushBack(&plist, 3);
    SLTPushBack(&plist, 6);
    SLTPushBack(&plist, 7);
    SLTPushBack(&plist, 4);
    SLTPushBack(&plist, 2);
    SLTPushBack(&plist, 6);
    partition(plist,4);
    SLTPrint(plist);
	return 0;
}

感谢阅读!
本文系个人理解,如有错误或不足之处,欢迎各位博友指正!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值