问题
给单链表排序(升序排列,要保持稳定性),要求通过改变结点的next指针从而改变结点的位置,而不是只交换结点的值来使得其有序!时间复杂度为O(N^2),空间复杂度为O(1)。已知链表结点的实现如下:
struct ListNode
{
int value;
ListNode* next;
ListNode(int v)
: value(v), next(NULL) {}
};
思路
这里很明显就是要我们做插入排序了,当然,冒泡也不是不可以,只是冒泡写起来麻烦,且性能是最差的。
插入排序怎么写呢?
这个算法的思想是这样的:
1. 维护两部分,一是已排序的部分,一是待排序的部分;
2. 一开始已排序部分为NULL;
3. 每次取出待排序部分的第一个元素A,和已排序的部分逐个比较(从头往后或从后往前都可以,不过单链表只能够从头往后比较),找到第一个大于A的元素B;
4. 将A插在B的前面一个位置(这时需要注意了,如果B原来是链表头,那么A将变成新的链表头,此时要记得更新链表头指针)。
代码
#include <iostream>
#include <string>
using namespace std;
struct ListNode
{
int value;
ListNode* next;
ListNode(int v)
: value(v), next(NULL) {}
};
ListNode* sortList(ListNode* head) {
// 注意这样写,是不需要额外判断head是否为NULL的
ListNode *newHead = NULL, *toInsert = head;
while (toInsert != NULL) {
ListNode *current = newHead, *last = NULL, *next = toInsert->next;
// 从头往后找到第一个大于toInsert->value的元素
while (current != NULL && current->value <= toInsert->value) {
last = current;
current = current->next;
}
if (last == NULL) {
// 如果比任何已排序的数字都要小,那么就成为新的头部
toInsert->next = newHead;
newHead = toInsert;
} else {
// 否则插入到last的后面
toInsert->next = last->next;
last->next = toInsert;
}
toInsert = next;
}
return newHead;
}
// 打印链表
void display(ListNode* head) {
while (head != NULL) {
cout << head->value << ' ';
head = head->next;
}
cout << endl;
}
int main() {
ListNode* head = new ListNode(5);
head->next = new ListNode(4);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(2);
head->next->next->next->next = new ListNode(1);
display(head);
ListNode* head2 = sortList(head);
display(head2);
return 0;
}