数据结构之排序(四)——选择排序(简单选择排序、堆排序)

简单选择排序

  • 基本思想:在待排序的数据中选出最大(小)的元素放在其最终的位置。
  • 基本操作
    1.首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将其与第一个记录交换
    2.再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将其与第二个记录交换
    3.重复上述操作,共进行n-1趟排序后,排序结束。
    在这里插入图片描述
    在这里插入图片描述
  • 算法描述
void SelectSort(SqList &K)
{
	for (i = 1; i < L.length; ++i)
	{
		k = i;
		for (j = i + 1; j <= L.length; j++)
			if (L.r[j].key < L.r[k].key)   
				k = j;                      //记录最小元素的位置
		if (k != i)
		{
			L.r[0] = L.r[i];                //交换
			L.r[i] = L.r[k];
			L.r[k] = L.r[0];
		}	
	}
}
  • 性能分析
    • 时间复杂度
      • 记录移动次数
        • 最好情况:0
        • 最坏情况:3(n-1)
      • 比较次数:无论待排序序列处于什么状态,选择排序所需进行的“比较次数”都相同, ∑ i = 1 n − 1 ( n − i ) = n 2 ( n − 1 ) \sum\limits_{i = 1}^{n - 1} {(n - i){\rm{ = }}\frac{n}{2}(n - 1)} i=1n1(ni)=2n(n1)
    • 稳定性:简单选择排序是不稳定排序 ,但可以改进,将其变成稳定的。
    • 空间复杂度:需要一个辅助空间,空间复杂度为 O ( 1 ) O(1) O(1)


堆排序

    • 定义: 若n个元素的序列 { a 1 , a 2 , ⋯ &ThinSpace; , a n } \{a_1,a_2,\cdots,a_n\} {a1,a2,,an}满足
      { a i ≤ a 2 i a i ≤ a 2 i + 1 &ThickSpace;&ThickSpace;&ThickSpace;&ThickSpace; 或 &ThickSpace;&ThickSpace;&ThickSpace;&ThickSpace; { a i ≥ a 2 i a i ≥ a 2 i + 1 \left\{ {\begin{array}{l} {{a_i} \le {a_{2i}}}\\ {{a_i} \le {a_{2i + 1}}} \end{array}} \right.\;\;\;\;或\;\;\;\;\left\{ {\begin{array}{l} {{a_i} \ge {a_{2i}}}\\ {{a_i} \ge {a_{2i + 1}}} \end{array}} \right. {aia2iaia2i+1{aia2iaia2i+1
      则分别称该序列 { a 1 , a 2 , ⋯ &ThinSpace; , a n } \{a_1,a_2,\cdots,a_n\} {a1,a2,,an}小根堆大根堆


      从堆的定义可以看出,堆的实质是满足如下性质的完全二叉树:二叉树中任一非叶子结点均小于(大于)它的孩子结点。

    • 例子
      在这里插入图片描述
      在这里插入图片描述

    • 堆排序:若在输出堆顶的最小值(最大值)后,使得剩余n-1个元素序列重新建成一个堆,则得到n个元素的次小值(次大值)…如此反复,便能得到一个有序序列,这个过程称之为堆排序。(每次从堆顶取一个元素)

    • 需解决的问题

      • 如何从一个无序序列建成一个堆?
      • 如何在输出堆顶元素后,调整剩余元素为一个新的堆?

下面主要从这两个问题出发,先介绍第二个问题的解决方法,再介绍第一个问题的解决方法。

  • 堆调整
    • 以小根堆为例
      • 输出堆顶元素后,以堆中最后一个元素替代之;
      • 然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换;
      • 重复上述过程,直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”。
    • 例子说明 :小根堆如下,
      在这里插入图片描述
      1.输出堆顶元素13,用最后一个元素97替换堆顶元素,
      在这里插入图片描述
      2.将此时的根结点(值为97的元素)与左右孩子进行比较,并与其中的较小者发生交换, 在这里插入图片描述
      3.重复步骤2,直到元素97为叶子结点,此时调整完成,输出堆顶元素27, 在这里插入图片描述
    • 算法描述
void HeapAdjust(elem R[], int s, int m)
{
	rc = R[s];
	for (j = 2 * s; j <= m; j *= 2)
	{
		if (j < m&&R[j] < R[j + 1])
			++j;
		if (rc >= R[j])
			break;
		R[s] = R[j];
		s = j;
	}
	R[s]=rc
}

可以看出,对一个无序序列反复“筛选”就可以得到一个堆;即,从一个无序序列建立堆的过程就是一个反复“筛选”的过程。

  • 建立堆
    • 由于堆实质上是一个线性表,那么我们可以顺序存储一个堆

    • 例子:有关键字{49,38,65,97,76,13,27,49}的一组记录,将其按关键字调整为一个小根堆。
      具体步骤
      1.按顺序存储,建立线性表,
      在这里插入图片描述
      2.所有叶子结点都是一个堆,所以不用调整,只需要调整非叶子结点,即上图中的97,38,65,49。从最后一个非叶子结点开始,依次向前调整。最后一个非叶子结点为第 n / 2 n/2 n/2个元素,将97与其左右孩子比较,发现97>49,则要交换97和49。
      在这里插入图片描述
      3.再以序号为 n / 2 − 1 n/2-1 n/21的结点为根的二叉树调整为堆,即上面所说的堆调整方法,此时,是65元素与左右孩子比较,交换65和13,
      在这里插入图片描述
      4.再以序号为 n / 2 − 2 n/2-2 n/22的结点为根的二叉树调整为堆,即上面所说的堆调整方法,此时,是38元素与左右孩子比较,不用交换。
      在这里插入图片描述
      5.再以序号为 n / 2 − 3 n/2-3 n/23的结点为根的二叉树调整为堆,即上面所说的堆调整方法,此时,是49元素与左右孩子比较,交换49和13。
      在这里插入图片描述
      6.此时还没结束,因为要调整到叶子结点才算结束,此时的49还要与其左右孩子比较,交换49和27。至此,整个无序的树被调整为一个小根堆,
      在这里插入图片描述

    • 对于堆的建立,用以下语句可以实现

for (i = n / 2; i >= 1; i--)
            HeapAdjust(R, i, n);
  • 堆排序算法描述
void HeapSort(elem R[])               //堆R[1]到R[n]进行堆排序
{
	int i;
	for (i = n / 2; i >= 1; i--)
		HeapAdjust(R, i, n);           //建初始堆
	for (i = n; i > 1; i--)            //进行n-1趟排序
	{
		Swap(R[1], R[i]);              //根与最后一个元素交换
		HeapAdjust(R, 1, i-1);         //对R[1]到R[i-1]重新建堆
	}
}
  • 性能分析
    • 初始化堆所需时间不超过 O ( n ) O(n) O(n);
    • 排序阶段
      • 依次重新建堆所需时间不超过 O ( l o g n ) O(logn) O(logn)
      • n-1次循环所需时间不超过 O ( n l o g n ) O(nlogn) O(nlogn)
    • 时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
    • 堆排序在最好和最坏的情况下都为 O ( n l o g n ) O(nlogn) O(nlogn),这是堆排序的最大优点。无论待排序序列的记录是正序还是逆序,都不会使堆排序处于“最好”或“最坏”状态。
    • 空间复杂度为 O ( 1 ) O(1) O(1),只需要一个用于记录交换的辅助存储空间。
    • 堆排序是一种不稳定的排序方法,它不适用于待排序记录个数n较少的情况,但对于n较大的文件还是很有效的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值