单向链表的排序-插入、归并与快排_单向链表的三种排序算法---快速排序,归并排序,插入排序

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

        //update pCur
        pCur = pNext;
    }
    return dummy.next;
}

##### 二、单向链表的归并排序


###### 题目:


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


###### 分析:


因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。   
 归并排序的一般步骤为:   
 1)将待排序数组(链表)取中点并一分为二;   
 2)递归地对左半部分进行归并排序;   
 3)递归地对右半部分进行归并排序;   
 4)将两个半部分进行合并(merge),得到结果。


所以对应此题目,可以划分为三个小问题:   
 1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);   
 2)写出merge函数,即如何合并链表。   
 3)写出mergesort函数,实现上述步骤。


不过这里需要**注意**的是:寻找链表的中点,当链表节点个数为偶数时,需要返回中值靠左的节点,比如当只有两个数时,返回第一个数位置的索引。目的是使分治结束。


###### 代码:


1. 快慢指针;2. 归并排序。   
 链表的归并排序空间复杂度是O(1)。



//找到链表中间位置(奇数中间那个,偶数偏左那个)
ListNode *Find_middle(ListNode *head)
{
if (!head || !head->next) return head;

//使用快,慢指针的方法:慢指针走一步,快指针走两步
ListNode \*slow = head, \*fast = head->next;
while (fast !=NULL && fast->next != NULL)
{
    slow = slow->next;
    fast = fast->next->next;
}
return slow;

}
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == NULL) return pHead2;
if (pHead2 == NULL) return pHead1;

ListNode mergeNode(0);
ListNode \*pNew = &mergeNode; //合并指针

while (pHead1 && pHead2)
{
    if (pHead1->val <= pHead2->val)
    {
        pNew->next = pHead1;
        pHead1 = pHead1->next;
    }
    else
    {
        pNew->next = pHead2;
        pHead2 = pHead2->next;
    }

    pNew = pNew->next;
}
if (pHead1)
    pNew->next = pHead1;
if (pHead2)
    pNew->next = pHead2;

return mergeNode.next;

}

ListNode *sortList(ListNode *head) {
if (head == NULL || head->next == NULL) return head;

ListNode \*pMid = Find_middle(head);
ListNode \*pRightHead = pMid->next;
pMid->next = NULL;

ListNode \*left = sortList(head);
ListNode \*right = sortList(pRightHead);

return Merge(left, right);

}


##### 三、单向链表的快速排序


###### 题目:


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


###### 分析:


单链表的快速排序 时间复杂度O(nlogn),空间复杂度O(n)


快速排序的主要操作是用选取的枢轴作为切割的基准,左侧所有元素均小于枢轴,右侧均不小于枢轴。经典实现是从头和尾两个方向进行处理,由于单链表的移动方向是**单向**的,所以必须寻求其他方式。


用一个指针遍历链表,遇到小于枢轴的元素,就将其移到链表的开始处,剩下的就是不小于枢轴的元素;为了实现上述目标,建立两个指针,一个指针指向所有元素都小于枢轴的子链表,一个指针用于遍历。


###### 代码:



//返回基准位置
ListNode *partitionList(ListNode* low, ListNode* high)
{
int pivot = low->val;

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值