作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【C/C++数据结构与算法】
分享:理想主义者和玩世不恭的人都觉得对方可怜,可他们实际都很幸运。——刘慈欣《球状闪电》
主要内容:八大排序选择排序中的直接选择排序、堆排序
下面图是在螺稷山游玩时拍的:
一、直接选择排序
1、思路
思路:最开始范围为0~size-1,先选出最大的和最小的数的下标把最大的和范围内开头begin下标的数交换。最小的和范围内末尾end下标的数交换然后begin++,end–,直到end和begin相遇。
2、复杂度
时间复杂度:O(n^2) ,按照上面的思路,第一次范围时为n,第二次为n-2…直到n-n或者n-1,所以,可以看出复杂度为O(n^2)
3、代码
// 选择排序1(优化版本)
void selectSort(int* arr, int size)
{
// 1、begin和end控制范围
int begin = 0;
int end = size - 1;
while (begin < end) {
// 2、每次缩小范围找出范围内maxi和mini
int maxi = begin;
int mini = begin;
for (int i = begin; i <= end; i++) {
if (arr[maxi] < arr[i]) {
maxi = i;
}
if (arr[mini] > arr[i]) {
mini = i;
}
}
// 3、交换元素
Swap(&arr[begin], &arr[mini]);// Swap是自己定义的交换函数
// 注意:在begin和最小值交换时,如果同时begin是范围内最大值,那就修正maxi为交换后的下标mini
if (maxi == begin) {
maxi = mini;
}
Swap(&arr[end], &arr[maxi]);
// 4、缩小范围
begin++;
end--;
}
}
// 选择排序2(排完一趟,只选出一个极端值,放在开头。然后start(开始位置++))
void SelectSort(int* arr, int size)
{
int cur_min_index = 0;
for (int i = 0; i < size - 1; i++) {
cur_min_index = i;
for (int j = i + 1; j < size; j++) {
if (arr[j] < arr[cur_min_index]) {
cur_min_index = j;
}
}
Swap(&arr[i], &arr[cur_min_index]);
}
}
二、堆排序
1、思路
思路:
先把数组建成一个大堆=》升序,开始时,排序调整范围是0~size-1,此时end=size-1,然后把堆顶和堆尾元素交换,这个交换到末尾的元素就在升序中有序了,排序范围-1。再用向下调整算法,把剩余的范围再调成大堆,再把堆顶和堆尾交换,直到end = 0结束。
总的来看,就是把第一大,次大,再次大的数依次从数组末尾往前放,从而达到排序的效果。
2、复杂度
时间复杂度:O(nlogn) ,向下调整的复杂度尾log(n),最多调整n个元素;建堆的复杂度约为n,所以T(n) = nlog(n) + n => 约等于nlogn。
不清楚向下调整和建堆复杂度可以看以下这篇博客,这里就不再做过多赘述。【建堆和向下调整算法】
3、代码
@ 辅助代码
// 建堆
void heapCreate(int* arr, int size)
{
for (int parent = (size - 1 - 1) / 2; parent >= 0; parent--) {
shiftDown(parent, size, arr);
}
}
// 向下调整算法(建堆时要用到)
void shiftDown(int parent, int size, int* arr)
{
int child = parent * 2 + 1;
while (child < size) {
if (child + 1 < size && arr[child] < arr[child + 1]) {
child++;
}
if (arr[child] > arr[parent]) {
Swap(&arr[child], &arr[parent]); // Swap函数是自定义的交换函数
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
@ 堆排序代码
// 堆排序
void heapSort(int* arr, int size)
{
// 1、建堆
heapCreate(arr, size);
// 2、用end划定范围
int end = size - 1;
while (end > 0) {
// 3、交换堆顶和堆尾元素
Swap(&arr[0], &arr[end]);
// 4、把剩下的通过向下调整重新变成堆
// 注意:此时,end由下标变为有效元素个数
shiftDown(0, end, arr);
// 5、范围-1
end--;
}
}