数据结构——选择排序

简单选择排序与堆排序:两种基本的排序算法详解

简单选择排序

算法原理
  1. iii趟,从所有元素中选择关键字最小的元素与A[i]A[i]A[i]交换
  2. 每趟排序可以确定一个元素的最终位置,通过n−1n-1n1趟排序后整个序列有序
代码实现
void SelectSort(int A[], int n){
	int i, j, min, k;
	for(i=1; i<n; i++){
		min = i;
		for(j=i+1; j<=n; j++)
			if(A[j] < A[min])
				min = j;
		if(min != i){
			k = A[i];
			A[i] = A[min];
			A[min] = k;
		}
	}
}
举例

在这里插入图片描述

性能分析
  • 空间效率:只使用常数个辅助单元,空间复杂度为O(1)O(1)O(1)
  • 时间效率:最好情况下,不需要交换元素;最坏情况下,交换3(n−1)3(n-1)3(n1)次。比较的次数是固定的,为n(n−1)2\frac{n(n-1)}{2}2n(n1)次,时间复杂度为O(n2)O(n^2)O(n2)
  • 稳定性:不稳定

堆排序

算法原理
  • 堆的定义:n个关键字序列A[1…n]称为堆,当且仅当序列满足
    A[i]>=A[2i]且A[i]>=A[2i+1]或(1)A[i]>=A[2i]且A[i]>=A[2i+1]或\tag{1}A[i]>=A[2i]A[i]>=A[2i+1](1)
    A[i]<=A[2i]且A[i]<=A[2i+1](1<=i<=⌊n/2⌋)(2)A[i]<=A[2i]且A[i]<=A[2i+1](1<=i<=\lfloor{n/2\rfloor})\tag{2}A[i]<=A[2i]A[i]<=A[2i+1](1<=i<=n/2)(2)
  • 可以将堆视为一棵完全二叉树,满足(1)(1)(1)的堆称为大根堆(大顶堆),满足(2)(2)(2)的称为小根堆(小顶堆)
  • 算法步骤(以大顶堆为例)
    1. 将n个元素的序列建成初始堆,输出堆顶元素
    2. 将堆底元素送入堆顶,从根开始向下调整,使其保持堆的性质,再输出堆顶元素
    3. 重复2,直到堆中仅剩下一个元素为止
  • 堆的调整
    1. 对第⌊n/2⌋\lfloor n/2 \rfloorn/2个结点为根的子树进行筛选(若根结点的关键字小于左右孩子中关键字较大者,则交换),使子树变成堆
    2. 向前依次对各个结点(⌊n/2⌋−1∼1\lfloor n/2\rfloor-1\sim 1n/211)为根的子树进行筛选,由于交换会破坏下一级的堆,于是继续筛选,构造下一级的堆,直到以该结点为根的子树变成堆为止。
    3. 重复第2步建堆,直到根结点
代码实现
void HeapAdjust(int A[], int k, int len){
	int i;
	A[0] = A[k];
	for(i=2*k; i<=len; i*=2){
		if(i<len && A[i]<A[i+1])
			i++;					// 孩子结点中关键字较大结点的下标
		if(A[0] > A[i])				// 若父结点的关键字大,不需要调整
			break;
		else{						// 父结点与较大孩子结点交换
			A[k] = A[i];
			k = i;					// 修改k值,向下调整堆
		}
	}
	A[k] = A[0];					// 被调整结点放入最终位置
}

void HeapSort(int A[], int len){
	int k;
	for(int i=len/2; i>0; i--)		// 初始化堆
		HeapAdjust(A, i, len);
	for(int i=len; i>1; i--){		// 交换堆顶元素到最终结果位置,并调整堆
		k = A[i];
		A[i] = A[1];
		A[1] = k;
		HeapAdjust(A, 1, i-1);
	}
}
举例

在这里插入图片描述

性能分析
  • 空间效率:仅使用了常数个辅助单元,空间复杂度为O(1)O(1)O(1)
  • 时间效率:建堆的时间为O(n)O(n)O(n),然后进行n−1n-1n1次调整,每次调整的时间复杂度为O(h)O(h)O(h),故在最好、最坏、平均情况下,堆排序的时间复杂度为O(nlog⁡2n)O(n\log_2n)O(nlog2n)
  • 稳定性:不稳定
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值