https://www.zhihu.com/question/51337272/answer/572455307
https://mp.weixin.qq.com/s/b1ICJaB5RjUjH_h_cB1qig
https://zhuanlan.zhihu.com/p/68672733
https://zhuanlan.zhihu.com/p/57088609
借用知乎大佬的图片:https://www.zhihu.com/question/51337272/answer/572455307
1.冒泡排序:注意最好情况
注意写法i从size-1开始写比较容易点:
void BubbleSort(vector<int>& arr) {
int size = arr.size();
for (int i = size-1; i >=0; i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j+1]) {
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j + 1] = tmp;
}
}
}
}
不过上面那种写法的话,即使遇到最好的情况仍然是O(n2);需要有一个标志位,标志有没有做过交换
https://blog.csdn.net/cloudeagle_bupt/article/details/85215357
public void bubbleSort(int arr[]) {
boolean didSwap;
for(int i = 0, len = arr.length; i < len - 1; i++) {
didSwap = false;
for(int j = 0; j < len - i - 1; j++) {
if(arr[j + 1] < arr[j]) {
swap(arr, j, j + 1);
didSwap = true;
}
}
if(didSwap == false)
return;
}
}
2.选择排序:注意不是稳定得
不是稳定的,例如1 5 6 5 4 ,有一次选择的时候把4和第一个5进行交换了
void SelectSort(vector<int>& arr) {
//每次选出一个最小的,然后放在最前面
int size = arr.size();
for (int i = 0; i < size ; i++) {
int index = i;
for (int j = i+1; j < size ; j++) {
if (arr[index] > arr[j]) {
index = j;
}
}
swap(arr[i], arr[index]);
}
}
3.插入排序:注意代码得实现
void InsertSort(vector<int>& arr) {
int size = arr.size();
for (int i = 1; i < size; i++) {
for (int j = i - 1; j >= 0&& arr[j] > arr[j+1]; j--) {
swap(arr[j], arr[j + 1]);
}
}
}
public class InsertSort {
public static int[] insertSort(int[] arr) {
if(arr == null || arr.length < 2)
return arr;
int n = arr.length;
for (int i = 1; i < n; i++) {
int temp = arr[i];
int k = i - 1;
while(k >= 0 && arr[k] > temp)
k--;
//腾出位置插进去,要插的位置是 k + 1;
for(int j = i ; j > k + 1; j--)
arr[j] = arr[j-1];
//插进去
arr[k+1] = temp;
}
return arr;
}
}
4.希尔排序:缩小增量排序
希尔排序的插入过程几乎于插入排序的过程,只是在外层多加了一个控制增量(gap)的循环罢了。
https://mp.weixin.qq.com/s/4kJdzLB7qO1sES2FEW0Low
public class ShellSort {
public static int[] shellSort(int arr[]) {
if (arr == null || arr.length < 2) return arr;
int n = arr.length;
// 对每组间隔为 h的分组进行排序,刚开始 h = n / 2;
for (int h = n / 2; h > 0; h /= 2) {
//对各个局部分组进行插入排序
for (int i = h; i < n; i++) {
// 将arr[i] 插入到所在分组的正确位置上
insertI(arr, h, i);
}
}
return arr;
}
/**
* 将arr[i]插入到所在分组的正确位置上
* arr[i]] 所在的分组为 ... arr[i-2*h],arr[i-h], arr[i+h] ...
*/
private static void insertI(int[] arr, int h, int i) {
int temp = arr[i];
int k;
for (k = i - h; k > 0 && temp < arr[k]; k -= h) {
arr[k + h] = arr[k];
}
arr[k + h] = temp;
}
}
关于InsertI有更好的写法
void insertI(int[] arr, int h, int i) {
int temp = arr[i];
int k;
for(k = i - h; k >= 0 && arr[k] > arr[k+h] ; k -= h) {
swap(arr[k], arr[k + h]);
}
}
5.桶排序:基数排序和计数排序(桶计基)
5.1桶排序(vector<Node*>)
可以发现有点像哈希表的那个结构
vector<Node*> bucket(n,new Node());
5.2计数排序(能够手写,并且有一个优化的版本的)
public class Counting {
public static int[] countSort(int[] arr) {
if(arr == null || arr.length < 2) return arr;
int n = arr.length;
int max = arr[0];
// 寻找数组的最大值
for (int i = 1; i < n; i++) {
if(max < arr[i])
max = arr[i];
}
//创建大小为max的临时数组
int[] temp = new int[max + 1];
//统计元素i出现的次数
for (int i = 0; i < n; i++) {
temp[arr[i]]++;
}
int k = 0;
//把临时数组统计好的数据汇总到原数组
for (int i = 0; i <= max; i++) {
for (int j = temp[i]; j > 0; j--) {
arr[k++] = i;
}
}
return arr;
}
}
5.3基数排序(vector<list<int>>)也可以申请九个队列
public class RadioSort {
public static int[] radioSort(int[] arr) {
if(arr == null || arr.length < 2) return arr;
int n = arr.length;
int max = arr[0];
// 找出最大值
for (int i = 1; i < n; i++) {
if(max < arr[i]) max = arr[i];
}
// 计算最大值是几位数
int num = 1;
while (max / 10 > 0) {
num++;
max = max / 10;
}
// 创建10个桶
ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(10);
//初始化桶
for (int i = 0; i < 10; i++) {
bucketList.add(new LinkedList<Integer>());
}
// 进行每一趟的排序,从个位数开始排
for (int i = 1; i <= num; i++) {
for (int j = 0; j < n; j++) {
// 获取每个数最后第 i 位是数组
int radio = (arr[j] / (int)Math.pow(10,i-1)) % 10;
//放进对应的桶里
bucketList.get(radio).add(arr[j]);
}
//合并放回原数组
int k = 0;
for (int j = 0; j < 10; j++) {
for (Integer t : bucketList.get(j)) {
arr[k++] = t;
}
//取出来合并了之后把桶清光数据
bucketList.get(j).clear();
}
}
return arr;
}
}