1、冒泡排序
基本介绍:
冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样逐渐向上冒。
代码实现:
/**
* 冒泡排序
* @param arr 待排序的数组
*/
public static void bubbleSort(int[] arr){
int len;
if (arr == null || (len = arr.length) < 2) return;
// 总共进行len-1趟
for (int i = 0; i < len - 1; i++) {
// 每趟都从下标小的开始,每完成一趟长度减一
for (int j = 1; j < len - i; j++) {
// 发现逆序,则交换
if (arr[j - 1] > arr[j]) {
swap(arr,j-1, j);
}
}
}
}
2、选择排序
基本介绍:
设一待排序的序列存于数组arr[n],第一次从a[0]~~a[n-1]中选取最大(小)的那个数然后与a[n-1](a[0])交换,第二次从a[0](a[1])~~a[n-2](a[n-1])中选取最大(小)的那个数与a[n-2](a[1])交换…第n-1次从a[0](a[n-2])~~a[1](a[n-1])中选取最大(小)的那个数与a[1](a[n-2])交换,共n-1次,得到一个有序序列。
代码实现:
/**
* 选择排序
* @param arr 待排序的数组
*/
public static void selectSort(int[] arr){
int len;
if (arr == null || (len = arr.length) < 2) return;
for (int i = len - 1; i > 0; i--) {
int max = arr[i],max_index = i;
// 找出最大值并记录下标
for (int j = 0; j < i; j++) {
if (arr[j] > max) {
max = arr[j];
max_index = j;
}
}
swap(arr,max_index,i);
}
}
3、插入排序
基本介绍:
将n个待排序的元素看成是一个有序表和一个无序表,初始时,有序表只有一个元素(可认为是a[0]),无序表有n-1个元素,然后就是将无序表中的元素依次取出放入有序表的合适位置,最终使得有序表有n个元素即前面所说的n个待排序的元素。
代码实现:
/**
* 插入排序
* @param arr 待排序的数组
*/
public static void insertSort(int[] arr){
int len;
if (arr == null || (len = arr.length) < 2) return;
/*for (int i = 1; i < len; i++) {
// 找插入的位置
int index = i;
while (index >0 && arr[index] < arr[index-1]) {
swap(arr,index,index - 1);
index--;
}
}*/
// 优化
for (int i = 1; i < len; i++) {
int index = i,value = arr[i];
while (index > 0 && value < arr[index-1]) {
arr[index] = arr[index - 1];
index--;
}
arr[index] = value;
}
}
4、希尔排序
基本介绍:
希尔排序是对插入排序的一种改进算法,也是一种插入排序,是希尔(Donald Shell)1959年提出的一种算法。将数组按一定增量分组,每一组使用插入排序进行排序,然后增量逐渐缩小,当缩小为1时,整个数组分为一组(这时的数组大部分元素已然有序),再进行插入排序。
代码实现:
/**
* 希尔排序
* @param arr 待排序的数组
*/
public static void shellSort(int[] arr){
int len;
if (arr == null || (len = arr.length) < 2) return;
// 定义步长
int gap = len / 2;
while (gap > 0) {
// 分为gap个组,对每一组都进行插入排序
for (int i = 0; i < gap; i++) {
for (int j = i+gap; j < len; j+=gap) {
int value = arr[j];
int index = j;
while (index >= gap && arr[index - gap] > value) {
arr[index] = arr[index - gap];
index-=gap;
}
arr[index] = value;
}
}
gap /= 2;
}
}
5、快速排序
基本介绍:
选择数组中一个元素(通常选择第一位)作为中轴pivot,使得数组中所有小于pivot的元素在pivot的左边,所有大于pivot的元素在pivot的右边,然后以pivot为分界线,递归的对左右两边进行上述操作,最终使得数组升序。
代码实现:
/**
* 快速排序
* @param arr 待排序的数组
* @param left
* @param right
*/
public static void quickSort(int[] arr, int left, int right){
if (left < right) {
// 方式一
/*int base = arr[left],j = left;
// 选取最左边的为基准,使得数组中左边的都小于等于基准,右边的都大等于于基准
for (int i = left + 1; i <= right; i++) {
if (arr[i] < base) {
j++;
swap(arr,i,j);
}
}
swap(arr, left, j);
quickSort(arr, left, j - 1);
quickSort(arr, j + 1, right);*/
// 方式二
int base = arr[left];
int i = left, j = right;
while (i < j) {
// 找到左边第一个比base大的数
while (i < j && arr[i] <= base) i++;
swap(arr,i,j);
// 找到右边第一个比base小的数
while (i < j && arr[j] >= base) j--;
swap(arr, i, j);
}
arr[j] = base;
quickSort(arr, left, j - 1);
quickSort(arr, j + 1, right);
}
}
6、归并排序
基本介绍:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
代码实现:
/**
* 归并排序
* @param arr 待排序的数组
* @param left
* @param right
*/
public static void mergeSort(int[] arr, int left, int right){
if (left == right) return;
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
int[] temp = new int[arr.length];
int i = left, j = mid+1, index = 0;
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[index++] = arr[i++];
}else {
temp[index++] = arr[j++];
}
}
while (i <= mid) temp[index++] = arr[i++];
while (j <= right) temp[index++] = arr[j++];
index = 0;
for (int k = left; k <= right; k++) {
arr[k] = temp[index++];
}
}
7、堆排序
基本介绍:
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。算法步骤为:
- 将待排序的数组调整(shift)为大顶堆(小顶堆)
- 将堆顶元素与最后一个元素交换,缩小范围继续调整(shift)
代码实现:
/**
* 堆排序
* @param arr 待排序的数组
*/
public static void heapSort(int[] arr){
int n;
if (arr == null || (n = arr.length) < 2) return;
// 先将数组调成大顶堆 从最后一叶子节点的父节点开始 即n/2-1
for (int i = n/2-1; i >= 0; i--) {
shift(arr, i, n);
}
// 将堆顶的数与最后一个叶节点交换 再调整 最终数组升序
for (int i = n - 1; i > 0; i--) {
swap(arr, 0, i);
shift(arr,0, i);
}
}
/**
* 调整下标i~j之间的元素
* @param arr 待排序的数组
* @param i
* @param j
*/
private static void shift(int[] arr, int i, int j){
// 设根节点为0 则节点为i的左子节点为2*i+1 右子节点为2*i+2
//int value = arr[i];
for (int left = 2*i+1; left < j; left = 2*i+1) {
// 选择左右子节点较大的一个
if (left+1 < j && arr[left] < arr[left+1]) {
left++;
}
if (arr[left] > arr[i]) {
swap(arr,i,left);
i = left;
}else {
break;
}
}
}
8、计数排序
基本介绍:
计数排序是一种牺牲空间换取时间的算法,使用数组的下标来定位元素,算法步骤为:
- 找出原数组中的最大值max和最小值min,计算桶数组的容量为max-min+1
- 遍历原数组中的元素,并记录于桶数组中
- 遍历桶数组,重新恢复于原数组中
代码实现:
/**
* 计数排序
* @param arr 待排序的数组
*/
public static void countSort(int[] arr){
int len;
if (arr == null || (len = arr.length) <2) return;
int max = arr[0],min = arr[0];
// 找出最大值和最小值
for (int i = 1; i < len; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
// 计算桶的个数
int count = max - min + 1;
int[] bucket = new int[count];
for (int i = 0; i < len; i++) {
bucket[arr[i]-min]++;
}
int index = 0;
// 遍历桶取出数据
for (int i = 0; i < count; i++) {
while (bucket[i] > 0) {
arr[index++] = i + min;
bucket[i]--;
}
}
}
9、桶排序
基本介绍:
桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里,每个桶子再个别排序。
代码实现:
/**
* 桶排序
* @param arr 待排序的数组
*/
public static void bucketSort(int[] arr){
int len;
if (arr == null || (len = arr.length) < 2) return;
// 找出最大值与最小值
int max = arr[0],min = arr[0];
for (int i = 1; i < len; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
// 计算桶的个数 间隔为10
int count = (max - min) / 10 +1;
List<Integer>[] bucket = new List[count];
for (int i = 0; i < len; i++) {
int index = (arr[i] - min) / 10;
if (bucket[index] == null) {
bucket[index] = new ArrayList<>();
}
bucket[index].add(arr[i]);
}
// 对每个桶里的元素分别排序
for (int i = 0; i < count; i++) {
if (bucket[i] == null) {
continue;
}
bucket[i].sort(null); // 默认升序
}
int index = 0;
// 依次取出桶里的元素
for (int i = 0; i < count; i++) {
if (bucket[i] == null) {
continue;
}
for (int num :
bucket[i]) {
arr[index++] = num;
}
}
}
10、基数排序
基本介绍:
将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行依次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
代码实现:
/**
* 基数排序
* @param arr 待排序的数组
*/
public static void radixSort(int[] arr){
int len;
if (arr == null || (len = arr.length) < 2) return;
// 找出数组里最大值
int max = arr[0];
for (int i = 1; i < len; i++) {
max = Math.max(max, arr[i]);
}
// 最大位数 即比较趟数
int n = String.valueOf(max).length(),index;
int[][] bucket = new int[10][len];
int[] indexOfBucket = new int[10];
for (int i = 0,m = 1; i < n; i++,m *= 10) {
for (int j = 0; j < len; j++) {
index = arr[j] / m % 10;
bucket[index][indexOfBucket[index]] = arr[j];
indexOfBucket[index]++;
}
index = 0;
for (int j = 0; j < 10; j++) {
for (int k = 0; k < indexOfBucket[j]; k++) {
arr[index++] = bucket[j][k];
}
indexOfBucket[j] = 0;
}
}
}
至此,十大排序算法介绍完毕,最后附上一张对各类算法的性能描述图: