基本思想
每一趟(第i趟,i = 0,1,2,…,n-2)在后面n-i个待排序的数据元素集合中选取关键码最小的数据元素,作为有序元素序列的第i个元素。待到第n-2趟做完,待排序元素结合中只剩下一个元素,排序结束
分类
- 直接选择排序
- 堆排序
直接选择排序
思想概述
1.在元素集合arr[i]~arr[n-1] 中选择关键码最大(最小)的数据元素
2.若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
3.在剩余的arr[i]~arr[n-2](arr[i+1]~arr[n-1])集合中,重复上述步骤,直到集合剩余1个元素
画图分析:
代码如下:
//直接选择排序
void SelectSort(int* arr, int size)
{
int minIdx = 0;
int start = 0; //记为无序区中第一个元素的下标
int i = size;
//此次循环执行size-2趟,当无序区元素个数为1时,循环结束
while (i-- > 1)
{
//1.在无序区中找最小元素的下标
int j = 0;
for (j = start; j < size; ++j)
{
if (arr[minIdx] > arr[j])
{
minIdx = j;
}
}
//2.已找到无序区中最小元素的下标,将最小元素与无序区的第一个元素交换(最小不为无序区第一个元素)
if (minIdx != start)
{
//交换函数
Swap(arr + start, arr + minIdx);
}
//3.无序区元素个数减1,即无序区第一个元素的下标加1
start++;
}
}
总结
- 排序算法稳定性的判断:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
- 直接选择排序算法时不稳定的。
- 时间复杂度为:O(n^2)
- 空间复杂度:O(1) —>在交换时使用
堆排序
思想概述
1.创建堆:升序 ---> 大堆,降序 ---> 小堆
循环执行下面步骤
(1)将堆顶元素arr[0]元素和当前堆中最后一个元素交换
(2)堆元素减1
(3)由于第一步后 根节点不再满足最大(小)堆定义,向下调整根节点
画图分析
代码如下:
//堆排序
void HeapSort(int* arr, int size)
{
Heap h;
int i = 0;
//1.创建最大堆
CreateHeap(&h, arr, size, Greater);
//2.循环进行一下步骤
for (i = h._size - 1; i >= 0; --i)
{
//(1)将堆顶元素与当前堆的最后一个元素交换--->
//因为每次交换结束后数据的最后一个已经排序好,所以待排序的元素减一,
//用i可以记录循环的次数,也可以记录待排序元素的个数
Swap(&h._hp[0], &h._hp[h._size - 1]);
//(2)堆元素个数减1
h._size--;
//(3)由于(1),堆中根节点不满足最大堆的性质,向下调整根节点
AdjustDown(&h, 0);
}
h._size = size;
//3.堆排序结束,将元素拷贝到源空间
memcpy(arr, h._hp, size*sizeof(int));
}
总结
- 每次将堆顶元素与无序区最后一个元素交换,由于不满足最大堆的定义,向下调整根节点的时间复杂度为O(log2n),由于堆中有n个元素,所以堆排序的时间复杂度为:O(n* log2n)
- 堆排序是一种不稳定的排序算法。