目录
前言
选择排序应该是最好理解的排序算法,核心思想就是在遍历数组找最大或最小的值将其放在最后,然后循环次数减一再重复以上操作。
由此可知选择排序是不稳定的排序。
选择排序也有一定缺陷,他会重复比较前面一些较小或较大元素,其时间复杂度为O(N^2)
相比之下堆排序效率更高。
选择排序
例如一个无序序列 5 1 2 3 4 0 ,我们先寻找里面的最大值5,找到后将5与最后一位元素交换,
然后循环的次数减一,再从剩下的序列中找最大值与最有一位元素交换,直到循环次数len小于2退出。
代码实现
void SelectSort(int* a, int n){ //n为数组长度
int max = 0; //max初始化为0号下标
int len = n; //用len记录数组长度
while (len>1){ //循环条件
for (int i = 0; i < len; ++i){
if (a[max] < a[i]) //遇到大于max下标的值时,max被赋值成该下标
max = i;
}
//循环结束后max下标上的值是最大的
Swap(&a[max], &a[len - 1]); //交换max和数组最后一位
len--; //循环次数减一
max = 0; //一定要将max置0
}
}
可以对以上代码进行一点小改进,每趟不仅找到最大值,还要找到最小值将最小值与最前面元素交换,然后循环次数减二,这样做虽然循环次数减半了,但时间复杂度没有变。
堆排序
堆排序也是选择排序的一种,如果要升序则建堆时选择大堆,降序选小堆。
核心思想就是,每次将堆顶元素和堆尾元素进行交换,如果是大堆的话,那么最大的元素就跑到了堆尾,然后除开堆尾,将剩下的元素重新排成大堆,再重复以上操作。
代码实现
void AdjustDwon(int* a, int start, int end){
int tmp = a[start];
for (int i = 2 * start + 1; i <= end; i = i * 2 + 1)
{
if (i < end&& a[i] < a[i + 1])//有右孩子并且左孩子小于右孩子
{
i++;
}//i一定是左右孩子的最大值
if (a[i] > tmp)
{
a[start] = a[i];
start = i;
}
else
{
break;
}
}
a[start] = tmp;
}
void HeapSort(int* a, int n){
//升序的话第一次建立大根堆,从后往前依次调整
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
AdjustDwon(a, i, n - 1);
}
//每次将根和待排序的最后一次交换,然后在调整
int tmp;
for (int i = 0; i < n - 1; i++)
{
tmp = a[0];
a[0] = a[n - 1 - i];
a[n - 1 - i] = tmp;
AdjustDwon(a, 0, n - 1 - i - 1);
}
}