# 常见排序算法
参考极客时间《数据结构与算法之美》专栏整理
## 常见排序算法对比
| 排序算法 | 时间复杂度 | 是否基于比较 |
| ---------------- | ---------- | :----------- |
| 冒泡、插入、选择 | O(n^2) | 是 |
| 快排、归并 | O(nlogn) | 是 |
| 桶、技术、基数 | O(n) | 否 |
## 排序算法的分析
### 排序算法的执行效率
* 最好情况、最坏情况、平均时间复杂度
* 时间复杂度的系数、常数、低阶
在数据量n很大的时候我们会忽略系数、常数、低阶,但如果针对数据量情况较小(10、100、1000这种量级),就需要把系数、常数、低阶考虑进来
* 比较次数和交换(或移动)次数
基于比较的排序算法的执行过程中,会涉及到元素的交换或移动。所以分析排序算法的执行效率的时候,也应该把比较次数和交换(或移动)次数考虑进去
### 排序算法的内存消耗
针对排序算法的空间复杂度,引入一个新的概念,**原地排序**(Sorted in place)。原地排序算法,就是特指空间复杂度是O(1)的排序算法。
### 排序算法的稳定性
**稳定性**指的是如果待排序中存在值相等的元素,经过排序后,相等元素之间原有的顺序不变。例如,一批订单数据,先按时间从最近往前开始进行排序,然后再按照金额从高到低排序。在保证排序算法稳定性的情况下最后结果金额能从高到低的同时下,相同金额的订单能从最近开始往后排,显然这样的排序结果更具有意义。
## 冒泡排序算法
`// 冒泡排序,a 表示数组,n 表示数组大小
public void bubbleSort(int[] a, int n) {
if (n <= 1) return;
for (int i = 0; i < n; ++i) {
// 提前退出冒泡循环的标志位
boolean flag = false;
for (int j = 0; j < n - i - 1; ++j) {
if (a[j] > a[j+1]) { // 交换
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
flag = true; // 表示有数据交换
}
}
if (!flag) break; // 没有数据交换,提前退出
}
}`
## 插入排序算法
`// 插入排序,a 表示数组,n 表示数组大小
public void insertionSort(int[] a, int n) {
if (n <= 1) return;
for (int i = 1; i < n; ++i) {
int value = a[i];
int j = i - 1;
// 查找插入的位置
for (; j >= 0; --j) {
if (a[j] > value) {
a[j+1] = a[j]; // 数据移动
} else {
break;
}
}
a[j+1] = value; // 插入数据
}
}`
## 选择排序算法
- 计算机基础
- 简答1
- 简答2
- 专案
- 浅谈0与1
- 浅谈TCP_IP
- 浅谈HTTP
- 浅谈HTTPS
- 数据结构与算法
- 常见数据结构简介
- 常用算法分析
- 常见排序算法
- Java数据结构类问题简答
- 专案
- HashMap
- 浅谈二叉树
- 算法题
- 算法001_TopN问题
- 算法002_汉诺塔
- 编程思想
- 杂说
- 观点_优秀程序设计的18大原则
- 设计模式_创建型
- 1_
- 2_
- 设计模式_结构型
- 1_
- 2_
- 设计模式_行为型
- 1_
- 2_
- Java相关
- 简答1
- 简答2
- 专案
- 浅谈String
- 浅谈Java泛型
- 浅谈Java异常
- 浅谈动态代理
- 浅谈AOP编程
- 浅谈ThreadLocal
- 浅谈Volatile
- 浅谈内存模型
- 浅谈类加载
- 专案_数据结构
- 浅谈SpareArray
- Android相关
- Android面试题
- 专案
- 推送原理解析
- Lint
- 自定义Lint
- Lint使用
- 优化案
- Apk体积优化
- Kotlin相关
- 简答1
- 简答2
- 三方框架相
- Okhttp3源码分析
- ButterKnife源码分析
- Glide4源码分析
- Retrofit源码分析
- RxJava源码分析
- ARouter源码分析
- LeakCanary源码分析
- WMRouter源码分析
- 跨平台相关
- ReactNative
- Flutter
- Hybrid
- 优质源
- 资讯源
- 组件源
- 推荐