失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 链表排序(冒泡 选择 插入 快排 归并 希尔 堆排序)

链表排序(冒泡 选择 插入 快排 归并 希尔 堆排序)

时间:2020-08-23 02:28:46

相关推荐

链表排序(冒泡 选择 插入 快排 归并 希尔 堆排序)

这篇文章分析一下链表的各种排序方法。

以下排序算法的正确性都可以在LeetCode的链表排序这一题检测。本文用到的链表结构如下(排序算法都是传入链表头指针作为参数,返回排序后的头指针)

struct ListNode {

int val;

ListNode *next;

ListNode(int x) : val(x), next(NULL) {}

};

插入排序(算法中是直接交换节点,时间复杂度O(n^2),空间复杂度O(1)

选择排序(算法中只是交换节点的val值,时间复杂度O(n^2),空间复杂度O(1)

快速排序1(算法只交换节点的val值,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))

这里的partition我们参考数组快排partition的第二种写法(选取第一个元素作为枢纽元的版本,因为链表选择最后一元素需要遍历一遍),具体可以参考here

这里我们还需要注意的一点是数组的partition两个参数分别代表数组的起始位置,两边都是闭区间,这样在排序的主函数中:

voidquicksort(vector<int>&arr,intlow,inthigh)

{

if(low < high)

{

intmiddle = mypartition(arr, low, high);

quicksort(arr, low, middle-1);

quicksort(arr, middle+1, high);

}

}

对左边子数组排序时,子数组右边界是middle-1,如果链表也按这种两边都是闭区间的话,找到分割后枢纽元middle,找到middle-1还得再次遍历数组,因此链表的partition采用前闭后开的区间(这样排序主函数也需要前闭后开区间),这样就可以避免上述问题

快速排序2(算法交换链表节点,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))

这里的partition,我们选取第一个节点作为枢纽元,然后把小于枢纽的节点放到一个链中,把不小于枢纽的及节点放到另一个链中,最后把两条链以及枢纽连接成一条链。

这里我们需要注意的是,1.在对一条子链进行partition时,由于节点的顺序都打乱了,所以得保正重新组合成一条新链表时,要和该子链表的前后部分连接起来,因此我们的partition传入三个参数,除了子链表的范围(也是前闭后开区间),还要传入子链表头结点的前驱;2.partition后链表的头结点可能已经改变

归并排序(算法交换链表节点,时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))本文地址

首先用快慢指针的方法找到链表中间节点,然后递归的对两个子链表排序,把两个排好序的子链表合并成一条有序的链表。归并排序应该算是链表排序最佳的选择了,保证了最好和最坏时间复杂度都是nlogn,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)

冒泡排序(算法交换链表节点val值,时间复杂度O(n^2),空间复杂度O(1))

对于希尔排序,因为排序过程中经常涉及到arr[i+gap]操作,其中gap为希尔排序的当前步长,这种操作不适合链表。

对于堆排序,一般是用数组来实现二叉堆,当然可以用二叉树来实现,但是这么做太麻烦,还得花费额外的空间构建二叉树

本文转自tenos博客园博客,原文链接:/TenosDoIt/p/3666585.html,如需转载请自行联系原作者

如果觉得《链表排序(冒泡 选择 插入 快排 归并 希尔 堆排序)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。