八大排序算法
目录
注意:以下排序均属于内部排序
-
(1)插入排序
-
(2)交换排序
-
(3)选择排序
-
(4)归并排序
-
排序总结分析表

一、插入排序

1. 直接插入排序
(1)整体思路
通过动图可以形象的理解到
-
1. 抽出一张牌,和当前元素之前的元素逐个比较,如果比当前元素小,该元素就后移,直到找到插入位置
-
说明:(惯用思想)初始时视第一个元素是有序的,之后通过排序逐渐增大有序序列的长度
(2)代码实现
第一种写法:while 循环(更规范)
public static void insert_sort(int[] arr) {for (int i = 1; i < arr.length; i++) {int insertvalue = arr[i];int j = i - 1;while (j >= 0 && insertvalue < arr[j]) {arr[j + 1] = arr[j]; j--;}arr[j + 1] = insertvalue;}
}
第二种写法:使用for 循环
public static void insert_sort_1(int[] arr) {for (int i = 1; i < arr.length; i++) {int insertvalue = arr[i];int j = i - 1;for (; j >= 0; j--) {if (insertvalue < arr[j]) {arr[j + 1] = arr[j];}else{break; }}arr[j + 1] = insertvalue;}
}
2. 折半插入排序
改进点:使用折半查找提高效率,使用循环遍历逐个匹配的效率太差
public static void binary_insert_sort(int[] arr) {for (int i = 1; i < arr.length; i++) {int insertvalue = arr[i];int left = 0;int right = i - 1; while (left <= right) {int mid = left + ((right - left) / 2);if (arr[mid] < insertvalue) {left = mid + 1;} else {right = mid - 1;}}for (int j = i - 1; j >= right + 1; j--) {arr[j + 1] = arr[j]; }arr[right + 1] = insertvalue;}
}
3. 希尔排序
动图演示

使用间隔 gap,gap 逐渐递减,最后 gap 的值必须是一,每一轮排序对 gap 产生的序列进行排序
快速写希尔排序:把直接插入排序中 “ 1 ” 的位置全部替换成 “ gap ”
public static void shell_sort(int[] arr){int gap = arr.length / 2; while (gap >= 1) {shell(arr, gap);gap /= 2;}
}
public static void shell(int[] arr, int gap){for (int i = gap; i < arr.length; i++) {int insertvalue = arr[i];int j = i - gap;while(j >= 0 && insertvalue < arr[j]){arr[j + gap] = arr[j];j -= gap;}arr[j + gap] = insertvalue;}
}
二、交换排序
1. 冒泡排序
动图演示

(1)普通版本
public static void bubble_sort(int[] arr){for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if(arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}
(2)改进版本
亮点:通过变量标记的方式标记是否执行了交换操作,可以一定程度上减少比较次数
public static void bubble_sort_improve(int[] arr){for (int i = 0; i < arr.length - 1; i++) {int flag = 0; for (int j = 0; j < arr.length - 1 - i; j++) {if(arr[j] > arr[j + 1]){flag = 1; int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}if(flag == 0){break;}}
}
2. 快速排序
动图演示

主要思想:递归,双指针(对撞指针)
思路分析
-
把第一个元素当作枢纽,然后通过两个指针 left 和 right
-
-
right : 在后面找比枢纽小的元素搬到枢纽的前面
-
public static int partition(int[] arr, int left, int right) {int pivot = arr[left];while (left < right) {while (arr[right] >= pivot && left < right) {right--;}arr[left] = arr[right];while (arr[left] <= pivot && left < right) {left++;}arr[right] = arr[left];}arr[left] = pivot;return left;
}public static void quicksort(int[] arr, int left, int right) {if(left < right){int pivot = partition(arr,left,right); quicksort(arr,left,pivot - 1);quicksort(arr,pivot + 1,right);}
}
三、选择排序
1. 简单选择排序
动图演示

基本思路:选一个数,在这个数的后面找有没有比本身还小的,有就交换位置
优化点:在后面找一个最小的数,避免重复的覆盖,减少比较次数
区别冒泡排序的优化
-
冒泡排序中是比较相邻两个元素之间是否有序,如果有序就不交换位置
-
(1)普通版本
public static void select_sort(int[] arr){for (int i = 0; i < arr.length; i++) {for (int j = i + 1; j < arr.length; j++){if(arr[j] < arr[i]){int temp = arr[j];arr[j] = arr[i];arr[i] = temp;}}}
}
(2)改进版本
public static void select_sort_improve(int[] arr){for (int i = 0; i < arr.length; i++) {int min_index = i; for (int j = i + 1; j < arr.length; j++){if(arr[j] < arr[min_index]){min_index = j;}}if(min_index != i){int temp = arr[i];arr[i] = arr[min_index];arr[min_index] = temp;}}
}
2. 堆排序(二叉堆)
(1)基本介绍
-
堆的性质是符合完全二叉树的,在结构上是递归定义的树结构
-
-
1. 若一个非叶子节点节点的物理位置为 “ i ”
-
2. 若一个数组的元素可以构成一棵树,数组大小为 n
-
(1)最后一个元素(叶子节点)在树中的标号对应的数组下标是n / 2
-
补充:关于树中节点的序号和数组下标的关系
方法:从左到右,从上到下依次标号
图例(对应数组下标)
0/ \1 2/ \ / \3 4 5 6
-
分类
-
大根堆:对于完全二叉树中的任意一个节点,其值都大于或等于其子树中所有节点的值。这意味着大根堆的根节点是堆中最大的元素
-
大根堆示例
10/ \8 6/ \ / \5 3 2
小根堆示例
1/ \3 4/ \ / \6 8 9
(2)堆排序思想
-
1. 构建一个大根堆
-
从后面的=第一个非叶子节点(下标:n / 2 - 1)开始,依次递归的往上调整,使得整棵树形成大根堆的结构
-
-
交换思想:交换的过程就是排序的过程,把最大的和最小的交换,即把最大的放入有序区,数组从后往前依次递减排序
-
-
理解:在调整过程中,指向的最大根节点会发生变化,对根节点调整即可实现对左右子树的调整)
-
-
关于n - 1的说明
-
(1)进行n - 1 趟排序
-
-
(3)循环过程中,刚好对应堆的大小的变化,每一轮排序一个元素(交换的过程),堆中需要调整的元素总数减小一
堆排序代码
public static void heapify(int[] arr, int n, int i) {int max_index = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && arr[left] > arr[max_index]) {max_index = left;}if (right < n && arr[right] > arr[max_index]) {max_index = right;}if (max_index != i) {int temp = arr[i];arr[i] = arr[max_index];arr[max_index] = temp;heapify(arr, n, max_index);}
}
public static void heap_sort(int[] arr) {int n = arr.length;for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}for (int i = n - 1; i > 0; i--) {int temp = arr[0];arr[0] = arr[i];arr[i] = temp;heapify(arr, i, 0);}
}
四、归并排序
动图演示

思路:运用合并为有序序列的思想、递归思想,两个有序序列通过比较的方式合并成一个更长的有序序列,而比较的过程正好是排序的过程
小结:排序左区间,排序右区间,两个区间合并,然而排序的过程又是两个区间合并的过程,即采用递归思想
归并排序代码
五、基数排序