这里的测试数据来自于之前自己随便写的生成器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)
稳定性
关键字调整过程中,相同元素的相对位置可能会发生改变,因此是不稳定的