浅谈,堆排序,基数排序,归并排序,希尔排序。

堆排序:

堆排序是一种利用的堆的性质进行的选择排序;
堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:Key[i]<=key[2i+1]&&Key[i]<=key2i+2或者Key[i]>=Key[2i+1]&&key>=key[2i+2] 即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。

堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。

其基本思想为:
大顶堆:Key[i]>=Key[2i+1]&&key>=key[2i+2];
小顶堆: Key[i]<=key[2i+1]&&Key[i]<=key[2i+2];
再简单总结下堆排序的基本思路:

在这里插入图片描述

堆排序的基本思想是:
步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。
a.假设给定无序序列结构如下
在这里插入图片描述

2.此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。
在这里插入图片描述

3)找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。
在这里插入图片描述这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。
在这里插入图片描述
此时,我们就将一个无需序列构造成了一个大顶堆。

步骤二 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
a.将堆顶元素9和末尾元素4进行交换:
在这里插入图片描述
b.重新调整结构,使其继续满足堆定义
在这里插入图片描述c.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.
在这里插入图片描述后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

转载自堆排序

基数排序:

算法思想:基数排序又称为“桶子法”,从低位开始将待排序的数按照这一位的值放到相应的编号为0~9的桶中。等到低位排完得到一个子序列,再将这个序列按照次低位的大小进入相应的桶中,一直排到最高位为止,数组排序完成。

算法执行步骤:
(1)遍历序列找出最大的数(为的是确定最大的数是几位数);
(2)开辟一个与数组大小相同的临时数组tmp;
(3)用一个count数组统计原数组中某一位(从低位向高位统计)相同的数据出现的次数;
(4)用一个start数组计算原数组中某一位(从最低位向最高位计算)相同数据出现的位置;
(5)将桶中数据从小到大用tmp数组收集起来;
(6)重复(3)(4)(5)直到所有位都被统计并计算过,用tmp收集起来;
(7)将tmp数组拷回到原数组中;
图片展示:
在这里插入图片描述
效率分析

算法性能
在这里插入图片描述

时间复杂度:
在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))。
我们可以看出,基数排序的效率和初始序列是否有序没有关联。

空间复杂度
对于任何位数上的基数进行“装桶”操作时,都需要n+r个临时空间。

算法稳定性
在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是稳定的算法。

归并排序:

分治法
“分”的步骤:

在这里插入图片描述“治”的步骤:
在这里插入图片描述详细“治”的步骤:

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200816224100381.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyMzQ4Mjg0,size_16,color_FFFFFF,t_70#pic_center
在这里插入图片描述
在这里插入图片描述
(1)稳定性
 归并排序是一种稳定的排序。
(2)存储结构要求
 可用顺序存储结构。也易于在链表上实现。
(3)时间复杂度
 对长度为n的文件,需进行趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。
 (4)空间复杂度
  需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
注意:若用单链表做存储结构,很容易给出就地的归并排序
归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

希尔排序:

基本概念:
希尔排序按其设计者希尔(Donald Shell)的名字命名,它是一种基于插入排序的快速排序算法,要了解希尔排序,必须先掌握插入排序的原理与实现。
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作(且步长要小于数组长度)。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
过程如图:
在这里插入图片描述
简单例子分析:
待排序数组:
{6, 5, 3, 1, 8, 7, 2, 4, 9, 0}

第一次步长h=4,
那么数组按照步长可以拆分成4个小数组([0]6的意思是下标[0]的值为6)

{[0]6, [4]8, [8]9}
{[1]5, [5]7, [9]0}
{[2]3, [6]2}
{[3]1, [7]4}

对这4个小数组分别进行插入排序后,4个小数组变成:
{[0]6, [4]8, [8]9}
{[1]0, [5]5, [9]7}
{[2]2, [6]3}
{[3]1, [7]4}
合并起来就是:{6, 0, 2, 1, 8, 5, 3, 4, 9, 7}

第二次步长h=1,
那么数组按照步长只有1个数组了
{6, 0, 2, 1, 8, 5, 3, 4, 9, 7}

对这个数组进行一次插入排序后,最终顺序就成为:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

关于希尔排序的时间复杂度,与步长息息相关:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值