目录
选择排序
选择排序基本思想:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
一、直接选择排序
1.在元素集合array[i]—array[n-1]中选择关键码最大(小)的数据元素
2.若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
3.在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
排序过程图:
第一次选择排序
第二次选择排序
第三次选择排序
第四次选择排序
第五次选择排序
当start位置走到最后一个位置时则循环结束,不用继续找最小(最大)值了。
代码示例:
void SelectSort2(int* a, int n)
{
int start = 0;
int i = 0;
//n为数组集合的个数,n-1为最后一个元素数组下标 当start走到最后一个元素循环结束
for (start = 0; start < n - 1 ; start++)
{
int min = start;
//在数组下标[start,n-1]的范围中寻找最小的数
for (int j = start; j < n; j++)
{
//找最小值的数组下标
if (a[j] < a[min])
{
min = j;
}
}
//交换数据
Swap(&a[start], &a[min]);
}
}
直接选择排序优化版本
像图中所示,定义两个指针指向数组两边,遍历区间[left,right]的数找到最大值和最小值的数,随后最大的数与right交换,最小的数与left交换,循环结束后,再次重复此项步骤,当left==right时结束循环。
代码示例:
//选择排序 (头尾开始寻找)
void SelectSort1(int* a, int n)
{
int left = 0;
int right = n - 1;
//从两边开始往中间找
while (left < right)
{
int minIndex = left;
int maxIndex = right;
for (int i = left; i <= right; i++)
{
//找最小值
if (a[i] < a[minIndex])
{
minIndex = i;
}
//找最大值
if (a[i] > a[maxIndex])
{
maxIndex = i;
}
}
Swap(&a[left], &a[minIndex]);
//修正
if (left == maxIndex)
{
maxIndex = minIndex;
}
Swap(&a[right], &a[maxIndex]);
left++;
right--;
}
}
但是这个方法有个细节需要注意:
如果最大值的位置位于left直接交换会导致意想不到的后果如下图所示,所以要进行一步判断并且修正为:maxinedx=minindex
总结
直接选择排序的特性总结:
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定
二、堆排序
在学习堆排序之前一定要知道什么是堆,如何构建堆,如果对此不是很清晰可以参考这篇文章来复习一下:堆
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
对于一个数组例如[20,17,4,16,5,3]排序过程如下
当排完序后对应的数组为[3,4,5,16,17,20],此处是升序所以在此之前我们建的是大堆。
代码示例
//堆排序
void HeapSort(int* a, int n)
{
//构建大堆
int parent = (n - 1 - 1)/2;
for (parent; parent>=0; parent--)
{
AdjustDown(a, n, parent);
}
//交换 排序(大堆升序)
int i = 0;
for (i = n-1; i > 0; i--)
{
Swap(&a[0], &a[i]);
AdjustDown(a, i, 0);
}
}
向下调整建堆的代码:
//向下调整算法
void AdjustDown(int* a, int n,int parent)
{
int child = parent * 2+1;
while (child < n )
{
//判断左右孩子哪个最大,建大堆
if (child + 1 < n && a[child + 1] > a[child])
{
child++;
}
if (a[parent] < a[child])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
总结
堆排序的特性总结:
1. 堆排序使用堆来选数,效率就高了很多。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(1)
4. 稳定性:不稳定