前言
在本篇博客中,作者将会你理解和实现选择排序和堆排序。
一.选择排序
1.排序思想
选择排序的思想是在一组数中选出最大(或最小)的值,然后把它放到最后一个(或第一个)位置,接着选出次大(或次小)的值,把它放到倒数第二个(或第二个)位置,以此类推。
如下图所示:
2.单趟排序
绝大部分排序都可以分为单趟排序和多趟排序,在我们写排序时,可以先写单趟排序,再写多趟排序,这可以使得写起来更加简单易懂。
单趟排序如上图所示。
①单趟排序伪代码实现
void Swap(int* num1, int* num2)//用于交换数组中的两个数
{
int tmp = *num1;
*num1 = *num2;
*num2 = tmp;
}
int max = 0;//需要找的最大值
int begin = 0;//待排数组的起始位置
int end = sz - 1;//待排数组的终止位置
for (int i = begin; i < end; i++)//找最大值
{
if (arr[i] > arr[max])
{
max = i;
}
}
Swap(&arr[end], &arr[max]);//将最大值换到末尾
3.多趟排序
在完成单趟排序后,只是将一个最大值排到了最后,接下来需要将剩余的数也进行排序,所以需要在单趟排序的外层嵌套一层循环来控制end的值。
①多趟排序代码实现
void Swap(int* num1, int* num2)//用于交换数组中的两个数
{
int tmp = *num1;
*num1 = *num2;
*num2 = tmp;
}
void SelectSort(int* arr, int sz)
{
for (int i = sz - 1; i > 0; i--)//外层循环控制end的位置
{
int max = 0;
int begin = 0;
int end = i;
for (int i = begin; i < end; i++)//内层循环用于单趟排序
{
if (arr[i] > arr[max])
{
max = i;
}
}
Swap(&arr[end], &arr[max]);
}
}
4.时间复杂度和空间复杂度
时间复杂度:看的是最坏的情况,但选择排序不管是已经有序还是完全逆序,依然需要比较,所以它的时间复杂度为1+2+3+4+……+(n-1)为O(n²)。
空间复杂度:在进行排序时,只用到一些临时变量的空间,没有额外开辟空间,所以空间复杂度为:O(1)。
二.堆排序
在博主的下面这篇博客中,有详细的讲到堆,其中也讲了堆排序,如果有需要看堆排序详解的可以看看下面这篇博客。
堆排序的要点是需要建堆,所以看的时候,要先看建堆部分。
三.稳定性分析
什么是稳定性?
稳定性是,如果一组数里面有两个相同的数,则排序完成后,如果不会改变他们的相对顺序,则这个排序算法是稳定的,否则是不稳定的。
结论
选择排序是不稳定的
堆排序也是不稳定的
四.所有源代码
#include<stdio.h>
void Print(int* arr, int sz)//打印数组
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void Swap(int* num1, int* num2)//交换数组中的两个数
{
int tmp = *num1;
*num1 = *num2;
*num2 = tmp;
}
void SelectSort(int* arr, int sz)//选择排序
{
for (int i = sz - 1; i > 0; i--)
{
int max = 0;
int begin = 0;
int end = i;
for (int i = begin; i < end; i++)
{
if (arr[i] > arr[max])
{
max = i;
}
}
Swap(&arr[end], &arr[max]);
}
}
void AdjustDown(int* arr, int sz, int root)//向下调整算法,用于堆排序
{
int parent = root;
int child = 2 * parent + 1;
while (child < sz)
{
if ((child + 1) < sz && arr[child + 1] > arr[child])
{
child++;
}
if (arr[child] > arr[parent])
{
Swap(&arr[child], &arr[parent]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
void HeapSort(int* arr, int sz)//堆排序
{
for (int i = (sz - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(arr, sz, i);
}
for (int i = sz - 1; i > 0; i--)
{
Swap(&arr[0], &arr[i]);
AdjustDown(arr, i, 0);
}
}
int main()
{
int arr1[] = { 15,48,96,20,13,5,74,18,2 };
int arr2[] = { 51,14,2,3,5,4,9,78 };
SelectSort(arr1, sizeof(arr1) / sizeof(int));
HeapSort(arr2, sizeof(arr2) / sizeof(int));
Print(arr1, sizeof(arr1) / sizeof(int));
Print(arr2, sizeof(arr2) / sizeof(int));
return 0;
}