LeetCode之148_Sort List

题目:Sort a linked list in O(n log n) time using constant space complexity.

              对一个单链表进行排序,要求时间复杂度为O(n log n),空间复杂度为常量

分析:在排序中快速排序,堆排序,归并排序等都是可以在O(n log n)的时间复杂度之内完成的。

a)      快速排序可以进行空间复杂度为1的原地排序,但必须是在可以反向索引的情况下,例如通过下标的减法向前索引,或者通过双向指针进行索引(双向链表)

b)      堆排序必须要大小为n的额外空间,不考虑。

c)       归并排序理论上也是需要n的额外空间的(合并的时候),但是考虑到此次是链表的特殊情况,可以借助链表的插入这种方式进行破坏性的操作来达到排序的目的,即不改变每个节点中的元素,每次到合并的时候就通过修改next指针重新组成一条新的链表。最终达到常量空间O(n log n)时间的单链表排序,具体细节见代码。

 

代码如下:

 在leetcode中提交时,只需拷贝class中的函数即可,此处完整的cpp文件是为了更好的模拟执行过程

#include<iostream>
using namespace std;

//Sort a linked list in O(n log n) time using constant space complexity.
//尝试使用归并排序,待排序元素为单链表
struct ListNode {
	int val;
	ListNode *next;
};

class Solution {
public:
	ListNode *sortList(ListNode *head) 
	{
		ListNode * retHead = NULL;
		int listLen = GetLen(head);
		if (listLen < 2)
		{
			return head;
		}
		retHead = MergeSort(head,listLen);
		return retHead;

	}

	//获取距离head长度为len-1距离的节点指针
	ListNode* GetMid(ListNode*head , int len)
	{
		ListNode *temp = head;
		for (int i = 1; i< len; i++)
		{
			head = head->next;
		}
		return head;
	}

	//归并排序
	ListNode* MergeSort(ListNode* head, int len)
	{
		if (len == 1)
		{
			return head;
		}
		int mid = len/2;
		ListNode *secondHead = GetMid(head, mid+1);         
		head = MergeSort(head, mid);
		secondHead = MergeSort(secondHead,len-mid);
		head = CombinList(head,mid,secondHead,len-mid);
		return head;
	}

	//为了减少储存空间,只有破坏链表的原有结构,重组链表达到排序的目的
	ListNode* CombinList(ListNode *pList1,int len1, ListNode* pList2,int len2)
	{
		int sum = len1+len2;
		ListNode* retHead = NULL;
		ListNode* retTail = NULL;
		ListNode* nextLink = GetMid(pList2,len2+1);   //指向下一条链表的头结点
		ListNode * exList = NULL;  //用于指向交互结点的指针

		if (pList1->val > pList2->val)             //确定返回的头结点
		{
			retHead = pList2;
			pList2 = pList2->next;
			len2--;
		}
		else
		{
			retHead = pList1;
			pList1 = pList1->next;
			len1--;

		}
		retTail = retHead;
		while (len1 != 0 && len2 != 0)
		{
			if (pList1->val > pList2->val)
			{
				retTail->next = pList2;
				retTail= retTail->next;
				pList2 = pList2->next;
				len2--;
			}
			else
			{
				retTail->next = pList1;
				retTail=retTail->next;
				pList1 = pList1->next;
				len1--;
			}
		}

		if (len1 == 0)
		{
			retTail->next = pList2;
		}
		else
		{
			retTail->next = pList1;
			while (len1 > 1)
			{
				pList1= pList1->next;
				len1--;
			}
			pList1->next = nextLink;
		}
		return retHead;
	}


	//获取链表的长度,时间复杂度为n
	int GetLen(ListNode *head)
	{
		int len = 0;
		while (head!=NULL)
		{
			len++;
			head = head->next;
		}
		return len;
	}
};

void printList(ListNode* head)
{
	cout<<endl;
	while (head != NULL)
	{
		cout<<head->val<<" ";
		head=head->next;

	}
	cout<<endl;
}
int main()
{
	ListNode *head = new ListNode;
	ListNode *tail = head;
	head->val = 4;
	head->next = NULL;
	for (int i = 0; i< 19; i++)
	{
		ListNode* temp = new ListNode;
		temp->val = rand()%90;
		temp->next = NULL;
		tail->next = temp;
		tail = tail->next;
	}
	printList(head);
	Solution a;
	head = a.sortList(head);
	printList(head);
	system("pause");
	return 0;
}

模拟排序前后结果为:



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值