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;
}
感谢阅读!
本文系个人理解,如有错误或不足之处,欢迎各位博友指正!!!