链表排序 Sort List

问题:

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

思路:

按时间复杂度,和空间复杂度,可以确定基本为快排和归并排序。关于算法的空间复杂度和时间复杂度有一个超赞的博客--常用的排序算法的时间复杂度和空间复杂度

具体实现:

-------------------快排法------------------

    void swap(int &a, int &b) //交换函数
    {
    	int c = a + b;
    	a = c - a;
    	b = c - a;
    }
    ListNode* sort(ListNode * left, ListNode * right)
    {
    	if(left == right ) return left;
    	ListNode *p1 = left,*p2  = p1->next,*p3 = NULL; 
    	if(p2 == NULL) return left;	
    	if(p2->val < p1->val) swap(p2->val, p1->val);
    	if(p2 == right) return left;
    	p3 = p2->next;
    	if(p3 == NULL) return left;
    	if(p3->val < p2->val) swap(p3->val, p2->val);
    	if(p2->val < p1->val) swap(p2->val, p1->val);
    	if(p3 == right) return left;
    //上面的代码主要为了完成在前三个值中选取中间值作为后面的比较
    	ListNode * mid = p2;
    	for(ListNode *p = p3; p != right; )
    	{
    		ListNode *np = p->next;
    		if(np != NULL && np->val < mid->val) //插入到mid前
    		{
    			p->next = np->next;
    			np->next = left;
    			left = np;
    		}
    		else
    		{
    			p = p->next;
    		}
    	}
    	ListNode * temp = sort(mid->next,right); //递归
    	mid->next = temp;
    	ListNode * head = sort(left, mid);//递归
    	
    	return  head;		
    }
分析:快排的平均时间复杂度是符合要求的,但是最差情况时间复杂度是O(n²)。所以为了初步解决,采用对前三个数据选取中间值作为比较数据。也可以使用随机位置作为比较数据(但是链表中不合适,数组较为合适)。RumTime 1576ms,勉强过了。

鉴于不心甘啊,所以我又去写了归并排序,中间折腾了蛮久的,印象深刻啊!也进一步思考了,蛮好的。

--------------归并排序--------------

    void swap(int &a, int &b)
    {
    	a = a ^ b;
    	b = b ^ a;
    	a = a ^ b;
    }
    ListNode* Merger(ListNode * head1, ListNode * head2)
    {
    	ListNode tm(0);
    	ListNode *head = &tm;
    	ListNode *p1 = head1, *p2 = head2, *ptemp = head;
    	while( p1 != NULL && p2 != NULL)
    	{
    		if(p1->val < p2->val)
    		{
    			ptemp->next = p1;
    			p1 = p1->next;
    		}
    		else
    		{
    			ptemp->next = p2;
    			p2 = p2->next;
    		}
    		ptemp = ptemp->next;
    	}
    	if(p1 != NULL) ptemp->next = p1;
    	if(p2 != NULL) ptemp->next = p2;
    	return head->next;
    }
    ListNode* MergerSort(ListNode* start)
    {
    	if(start == NULL || start->next == NULL)	return start;
    	ListNode *mid = start,  *p= start;
    	for(ListNode *p = start; p!= NULL && p->next != NULL && p->next->next != NULL; p = p->next->next)
    		mid = mid->next; //找中间位置
    	ListNode *midnext = mid->next;
    	mid->next = NULL;
    	ListNode *p1 = MergerSort(start);//递归
    	ListNode *p2 = MergerSort(midnext);    	
    	return Merger(p1, p2); //合并
    }
解析:1. 交换使用了位运算的异或,主要原理是 a = a^b^b.   b^b=00...0
   2. 归并算法是一种分治算法思想,对list其不断找中间值的方案是指针p1每次移2位,p2每次移1位,则p1到list尾时,p2为mid。

           3. 每次递归时列表尾为NULL,方便判读,所以先保存mid->next。之后将mid->next = NULL.

           4. 对于Merge两个list时,使用p->next连接。所以对于head需要特殊处理,采用先添加一个临时的无用节点,最后返回head->next.

结果:归并排序RunTime 224ms。过了


------尾声----

耗时了很久来写这个程序,很明显感受到自己的基础还不够扎实。有很多需要注意和学习的!加油~


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值