选择排序 和 冒泡排序
参考:《数据结构教程》李春葆
一,选择排序
0,有序区
有序区:数组中已经排序好的连续区间
1,算法思想(升序)
将有序区设在数组的开头 / 末尾,然后从无序区中选择一个最小值 / 最大值,交换到无区序的第一个元素 / 最后一个元素,作为新选择出来的元素添加到有序区。一直循环到无序区为空
2,算法步骤(升序)
① 有序区在数组前面
用 i 从 0 遍历到 n-1:i 指向无序区的第一个元素 且 遍历 n-1 个元素表示需要找到 n-1 个当前无序区的最大值
用 j 遍历无序区 (i ~ n-1),找到当前的最小值
② 有序区在数组后面
用 i 从 n-1 遍历到 1:i 指向无序区的最后一个元素 且 遍历 n-1 个元素表示需要找到 n-1 个当前无序区的最大值
用 j 遍历无序区 (0 ~ i),找到当前的最小值
3,代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define N 110 int a[N]; void swap(int i, int j) { int t = a[i]; a[i] = a[j]; a[j] = t; } void selectSort1(int n) // 升序,有序区在前面 { for (int i = 0; i < n; i++) { int k = i; for (int j = i; j < n; j++) if (a[j] < a[k]) k = j; swap(i, k); } } void selectSort2(int n) // 升序,有序区在后面 { for (int i = n - 1; i > 0; i--) { int k = i; for (int j = 0; j <= i; j++) if (a[j] > a[k]) k = j; swap(i, k); } } int main(void) { int n; while (scanf("%d", &n) != EOF) { for (int i = 0; i < n; i++) scanf("%d", &a[i]); selectSort1(n); selectSort2(n); for (int i = 0; i < n; i++) printf("%d ", a[i]); puts(""); } }
4,算法分析
空间复杂度:仅用常数个辅助单元,所以空间复杂度为 O(1)
时间复杂度:
比较次数:无论数组的状态如何,每一次循环总是要进行比较的,而外层循环需要循环 n 次(n-1 也按 n 算),对于外层的第 i 次循环,需要循环 i 次内循环,所以比较次数为 n * (n -1) / 2
移动次数:元素的移动只在外层循环中要交换元素的时候移动,每次交换需要移动 3 个元素,最多需要交换 m-1 次,因为最后一次必定不用交换,所以移动次数最多需要 3 * (m - 1) 次
所以时间复杂度为 O(n2)
稳定性:
在进行交换元素的时候,可能会导致第 i 个元素与其它含有相同值的元素的相对位置发生改变,所以选择排序是一种不稳定的排序算法
二,冒泡排序
1,算法思想
从后往前/从前往后两两比较相邻元素的值,若为逆序,则交换它们,直到某一趟没有发生交换或者序列比较完
2,算法步骤(升序)
① 有序区在数组前面
用 i 从 0 遍历到 n-1:i 指向无序区的第一个元素 且 遍历 n-1 个元素表示需要找到 n-1 个当前无序区的最大值
用 j 遍历无序区 (i ~ n-1),找到当前的最小值
② 有序区在数组后面
用 i 从 n-1 遍历到 1:i 指向无序区的最后一个元素 且 遍历 n-1 个元素表示需要找到 n-1 个当前无序区的最大值
用 j 遍历无序区 (0 ~ i),找到当前的最小值
3,代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define N 110 int a[N]; void swap(int i, int j) { int t = a[i]; a[i] = a[j]; a[j] = t; } void bubbleSort(int n) // 升序,有序区在后面 { for (int i = n - 1; i > 0; i--) { for (int j = 0; j < i; j++) // 两两比较,注意 j+1 不要越界 if (a[j] > a[j + 1]) swap(j, j + 1); } } int main(void) { int n; while (scanf("%d", &n) != EOF) { for (int i = 0; i < n; i++) scanf("%d", &a[i]); bubbleSort(n); for (int i = 0; i < n; i++) printf("%d ", a[i]); puts(""); } }
4,算法分析
空间复杂度:仅用常数个辅助单元,所以空间复杂度为 O(1)
时间复杂度:
最坏时间复杂度:O(n2),即逆序序列,比较次数,n(n-1)/2,移动次数,3n(n-1)/2
平均时间复杂度:O(n2)
稳定性:
因为冒泡排序只交换相邻的逆序对,所以不可能越过相等的元素,造成不稳定现象。即当 i > j,a[i] = a[j] 时,不会发生交换
三,比较
两者外层循环一模一样,内层循环的目的一样但实现方式不同:
选择排序是通过选择实现的,冒泡排序是通过比较实现的