1 选择排序
每一次从待排序的数据元素中选出最小(最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
2 直接选择排序
2.1 基本思想
- 在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
- 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
- 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
2.2 算法示意图
2.3 程序代码
#include<stdio.h>
#include<stdlib.h>
/*选择排序:每一次从未排序的数据中找到一个最小的,
把最小的放到未排序的数据的头部,不断重复
*/
void swap(int* arr, int pos1, int pos2) {
int tmp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = tmp;
}
void selectSort(int* arr, int n) {
//从未排序的序列中找到最值,存放到未排序的起始位置
//未排序区间
int start = 0;
int end = n - 1;
while (start < end) {
int minIdx = start;
for (int i = start + 1; i <= end; i++) {
if (arr[i] < arr[minIdx])
minIdx = i;
}
//把最小值存放在最开始的位置
swap(arr, start, minIdx);
//剩余的未排序区间[start + 1 , end]
start++;
}
}
2.4 验证代码
void testSelectSort() {
int arr[] = { 9 ,1,2,5,7,4,8,6,3,5 };
int n = sizeof(arr) / sizeof(arr[0]);
selectSort(arr, n);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
}
int main(){
testSelectSort();
return 0;
}
运行结果如下:
2.5 直接选择排序特性
- 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
- 时间复杂度: O ( N 2 ) O(N^2) O(N2)
- 空间复杂度: O ( 1 ) O(1) O(1)
- 稳定性:不稳定
2.6 选择排序的优化
每次选最大值和最小值,同时进行比较
#include<stdio.h>
#include<stdlib.h>
void selectSort2(int* arr, int n) {
int start = 0;
int end = n - 1;
//每次从未排序的区间中找到一个最大值,一个最小值
//min放在头部,max放在尾部
while (start < end) {
int maxIdx = start;
int minIdx = start;
for (int i = start + 1; i <= end; i++) {
if (arr[i] > arr[maxIdx])
maxIdx = i;
if (arr[i] < arr[minIdx])
minIdx = i;
}
swap(arr, start, minIdx);
//判断最大值是否为start
if (maxIdx == start)
maxIdx = minIdx;
swap(arr, end, maxIdx);
start++;
end--;
}
}
void testSelectSort2() {
int arr[] = { 9 ,1,2,5,7,4,8,6,3,5 };
int n = sizeof(arr) / sizeof(arr[0]);
selectSort2(arr, n);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
}
int main(){
testSelectSort2();
return 0;
}
3 堆排序
3.1 基本思想
堆排序是指利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。
需要注意的是排升序要建大堆,排降序建小堆。
3.2 算法示意图
3.3 程序代码
#include<stdio.h>
#include<stdlib.h>
typedef int HPDataType;
/*实现数组中两个位置值的交换*/
void Swap(HPDataType* arr, int idx1, int idx2) {
HPDataType tmp = arr[idx1];
arr[idx1] = arr[idx2];
arr[idx2] = tmp;
}
/*实现大根堆
向下调整算法,传入存储堆的数组及长度,需要执行向下调整的节点序号
*/
void bigShifDown(HPDataType* arr, int n, int cur) {
//找到孩子的位置
int child = cur * 2 + 1;
while (child < n) {
//存在孩子,比较两个孩子,找到值最小的一个
if (child + 1 < n && arr[child + 1] > arr[child])
child = child + 1;
//和当前数据进行比较
if (arr[cur] < arr[child]) {
//交换当前节点与值最小的孩子
Swap(arr, child, cur);
//更新位置,继续调整
cur = child;
child = 2 * cur + 1;
}
else
break;
}
}
//堆排序
void HeapSort(int* arr, int n) {
//建堆
for (int i = (n - 2) / 2; i >= 0; i--) {
bigShifDown(arr, n, i);
}
//堆排序
int end = n - 1;
while (end > 0) {
//堆顶元素的删除:交换+向下调整
Swap(arr, 0, end);
bigShifDown(arr, end, 0);
end--;
}
}
3.4 验证代码
void testHeapSort() {
int arr[] = { 9 ,1,2,5,7,4,8,6,3,5 };
int n = sizeof(arr) / sizeof(arr[0]);
HeapSort(arr, n);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
}
int main() {
testHeapSort();
return 0;
}
运行结果如下:
3.5 堆排序特性
- 堆排序使用堆来选数,效率就高了很多。
- 时间复杂度: O ( N l o g ( N ) ) O(Nlog(N)) O(Nlog(N))
- 空间复杂度: O ( 1 ) O(1) O(1)
- 稳定性:不稳定