选择排序——简单选择排序和堆排序

这里的测试数据来自于之前自己随便写的生成器https://blog.csdn.net/qq_37350078/article/details/101561041

#include<bits/stdc++.h>
using namespace std;

int main() {
	FILE *fp;
    if((fp = fopen("test.txt", "r")) == NULL)  
    	{ cout << "Error!"; }
    int T = 10, arr[20];
    while(T--) {//多组样例 
    	for(int i = 1; i <= 20; i++)  
    		fscanf(fp, "%d", &arr[i]);
	    cout << "排序前:";
	    for(int i = 1; i <= 20; i++)  
	    	cout << arr[i] << " ";
	    cout << endl << "排序后:"; 
	    //简单选择排序
	    SelectSort(arr, 20); 
	    //堆排序
	    HeapSort(arr, 20);
	   
		for(int i = 1; i <= 20; i++)  
			cout << arr[i] << " ";
	    cout << endl << endl; 
    }
	return 0;
} 
/*-----简单选择排序-----*/
void SelectSort(int arr[], int n) {
	/*从第 2个元素,对第 i个元素, 
	在其之后的个 n-i+1 个未排序元素中,
	查找一个最小的元素放到有序序列的第 i个位置上*/
    for(int i = 1; i < n; i++) {
    	int min = i;
    	for(int j = i+1; j < n; j++) {
    		if(arr[j] < arr[min]) 
				min = j; //更新最小元素位置
		}
		if(min != i) { //将最小元素交换至第 i个位置 
			int temp = arr[i];
			arr[i] = arr[min];
			arr[min] = temp;
		} 
	}
}

简单选择排序
空间复杂度
使用常数个辅助单元,空间复杂度为O(1)
时间复杂度
最好情况:初始序列已经有序,无需选择交换,但是比较次数为∑ (n-i) = n*(n-1)/2 次,时间复杂度为O(n²)
最坏情况:比较次数与序列的初始状态无关,依旧为∑ (n-i) = n*(n-1)/2 次,时间复杂度为O(n²)
平均情况:时间复杂度为O(n²)
稳定性
最小元素可能和相同元素中相对位置在前的元素互换,例如{2,2,1},最终排序为{1,2,2},因此是不稳定

/*-----堆排序-----*/
void BuildMaxHeap(int arr[], int len);
void AdjustDown(int arr[], int k, int len); 

void HeapSort(int arr[], int len) {
	BuildMaxHeap(arr, len); //初始化建立大根堆
	for (int i = len; i > 1; i--) {
		int temp = arr[i];
		arr[i] = arr[1];
		arr[1] = temp;
		//cout << arr[i] << endl; 
		AdjustDown(arr, 1, i-1);
	} 
}
 
void BuildMaxHeap(int arr[], int len) {
	for(int i = len/2; i > 0; i--)
		AdjustDown(arr, i, len); //调堆:将元素 arr[k]向下调整 
} 

void AdjustDown(int arr[], int k, int len) {
	arr[0] = arr[k];
	for(int i = 2*k; i <= len; i*=2) {
		if (i < len && arr[i] < arr[i+1]) //左结点小于右结点,指针 i指向右结点,否则指向左结点 
			i++;                
		if (arr[0] > arr[i])     //若子结点均小于双亲结点,则不调整,循环结束
			break;
		else {                   //否则交换 arr[0],arr[i](较大子结点)    
			arr[k] = arr[i];     //双亲结点值等于较大子结点 
			k = i;               //之后从 i开始调整下一层的结点 
		}
	} 
	arr[k] = arr[0];
} 

堆排序
?什么是堆?
实质:完全二叉树的顺序存储结构
这里采用的是大根堆算法
?什么是大根堆?
大根堆的性质:双亲结点的值大于其儿子节点的值
即L[ i ] > L[ 2i ] 且 L[i] > L[ 2i+1 ] (1 <= i <= n/2)
空间复杂度
使用常数个辅助单元,空间复杂度为O(1)
时间复杂度
建堆BuildMaxHeap() 时间为O(n)
之后有 n-1 次向下调堆AdjustDown() 操作,每次调整时间为O(h),对完全二叉树而言,h=log₂n向上取整,所以调堆过程时间为O((n-1)*log₂n),时间复杂度为O(nlogn)
在最好、最坏和平均情况下都是O(nlogn)
稳定性
关键字调整过程中,相同元素的相对位置可能会发生改变,因此是不稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值