【算法】排序算法(基數、歸併、快速、希爾、插入、選擇、冒泡)
1、基數排序
- 基數排序(radix sort)又稱桶排序(bucket sort),相對於常見的比較排序,基數排序是一種分配式排序,即通過將所有數字分配到應在的位置最後再覆蓋到原數組完成排序的過程。
1.1 圖解
1.2 代碼實現
package com.data.algorithm.sort;
/**
* 基數排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/29
*/
public class RadixSort {
public static void main(String[] args) {
int[] arr = new int[800000];
for (int i = 0; i < 800000; ++i) {
arr[i] = (int) (Math.random() * 800000.0D);
}
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
radixSort(arr);
Long endTime = System.currentTimeMillis() - startTime;
System.out.println("排序耗時:" + endTime + "毫秒");
System.out.println("排序耗時:" + endTime / 1000 + "秒");
}
/**
* 基數排序
* @param arr
*/
public static void radixSort(int[] arr) {
//1,找出數組中最大數的位數
int max = arr[0];
int maxLength;
for(maxLength = 1; maxLength < arr.length; ++maxLength) {
if (arr[maxLength] > max) {
max = arr[maxLength];
}
}
maxLength = String.valueOf(max).length();
//2、定義一個二維數組,表示10個桶
int[][] bucket = new int[10][arr.length];
//3、定義一個一維數組,來記錄每個桶裏有幾個數據
int[] bucketElementCounts = new int[10];
//4、循環
for(int n = 1,i = 0; i < maxLength; i++,n *= 10) {
for(int j = 0; j < arr.length; ++j) {
int of = arr[j] / n % 10;
bucket[of][bucketElementCounts[of]] = arr[j];
++bucketElementCounts[of];
}
for(int k = 0,index = 0; k < bucketElementCounts.length; ++k) {
if (bucketElementCounts[k] != 0) {
for(int l = 0; l < bucketElementCounts[k]; ++l) {
arr[index++] = bucket[k][l];
}
}
bucketElementCounts[k] = 0;
}
}
}
}
2、歸併排序
- 歸併排序是分治法的一個典型應用,其思想就是先遞歸分解數組,再合併數組。
2.1 圖解
2.2 代碼實現
package com.data.algorithm.sort;
/**
* 歸併排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/25
*/
public class MergetSort {
public static void main(String[] args) {
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; ++i) {
arr[i] = (int) (Math.random() * 80000000.0D);
}
int[] temp = new int[arr.length];
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
mergeSort(arr,0,arr.length-1,temp);
Long endTime = System.currentTimeMillis() - startTime;
System.out.println("排序耗時:" + endTime + "毫秒");
System.out.println("排序耗時:" + endTime / 1000 + "秒");
}
/**
* 歸併排序--歸併
* @param arr
* @param left
* @param right
* @param temp
*/
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
/**
* 歸併排序--排序
* @param arr
* @param left
* @param mid
* @param right
* @param temp
*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
while(i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
++t;
++i;
} else {
temp[t] = arr[j];
++t;
++j;
}
}
while(i <= mid) {
temp[t] = arr[i];
++t;
++i;
}
while(j <= right) {
temp[t] = arr[j];
++t;
++j;
}
t = 0;
for(int tempLeft = left; tempLeft <= right; ++tempLeft) {
arr[tempLeft] = temp[t];
++t;
}
}
}
3、快速排序
- 快速排序是一種排序執行效率很高的排序算法,它利用分治法來對待排序序列進行分治排序,它的思想主要是通過一趟排序將待排記錄分隔成獨立的兩部分,其中的一部分比關鍵字小,後面一部分比關鍵字大,然後再對這前後的兩部分分別採用這種方式進行排序,通過遞歸的運算最終達到整個序列有序。
3.1 圖解
3.2 代碼實現
package com.data.algorithm.sort;
/**
* 快速排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/24
*/
public class QuickSort {
public static void main(String[] args) {
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; ++i) {
arr[i] = (int) (Math.random() * 80000000.0D);
}
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
quickSort(arr,0,arr.length-1);
Long endTime = System.currentTimeMillis() - startTime;
System.out.println("排序耗時:" + endTime + "毫秒");
System.out.println("排序耗時:" + endTime / 1000 + "秒");
}
/**
* 快速排序
*
* @param
* @param left
* @param right
*/
public static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int pivot = arr[(left + right) / 2];
boolean var6 = false;
while(l < r) {
while(arr[l] < pivot) {
++l;
}
while(arr[r] > pivot) {
--r;
}
if (l >= r) {
break;
}
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if (arr[l] == pivot) {
--r;
}
if (arr[r] == pivot) {
++l;
}
}
if (l == r) {
++l;
--r;
}
if (left < r) {
quickSort(arr, left, r);
}
if (right > l) {
quickSort(arr, l, right);
}
}
}
4、希爾排序
- 希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本。希爾排序是非穩定排序算法。該方法因DL.Shell於1959年提出而得名。 希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。
4.1 圖解
4.2 代碼實現
package com.data.algorithm.sort;
/**
* 希爾排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/7
*/
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; ++i) {
arr[i] = (int) (Math.random() * 80000000.0D);
}
int[] arr2 = arr.clone();
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
shellSort2(arr);
Long endTime = System.currentTimeMillis() - startTime;
System.out.println("排序耗時:" + endTime + "毫秒");
System.out.println("排序耗時:" + endTime / 1000 + "秒");
Long startTime1 = System.currentTimeMillis();
System.out.println("開始排序");
shellSort3(arr2);
Long endTime1 = System.currentTimeMillis() - startTime1;
System.out.println("排序耗時:" + endTime1 + "毫秒");
System.out.println("排序耗時:" + endTime1 / 1000 + "秒");
}
/**
* 替換法希爾排序,效率不高
* @param arr
*/
public static void shellSort(int[] arr) {
int temp = 0;
for(int gap = arr.length / 2; gap > 0; gap /= 2) {
for(int i = gap; i < arr.length; ++i) {
for(int j = i - gap; j >= 0; j -= gap) {
if (arr[j] > arr[j + gap]) {
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
}
}
/**
* 移位法希爾排序
* @param arr
*/
public static void shellSort2(int[] arr) {
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; ++i) {
int j = i;
int temp = arr[i];
if (arr[i] < arr[i - gap]) {
while (j - gap >= 0 && temp < arr[j - gap]) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
}
}
/**
* 移位法希爾排序2
* @param arr
*/
public static void shellSort3(int[] arr) {
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; ++i) {
int temp = arr[i];
int insertIndex;
for(insertIndex = i - gap; insertIndex >= 0 && temp < arr[insertIndex]; insertIndex -= gap) {
arr[insertIndex + gap] = arr[insertIndex];
}
if (insertIndex + gap != i) {
arr[insertIndex + gap] = temp;
}
}
}
}
}
5、插入排序
- 插入排序(英語:Insertion Sort)是一種簡單直觀的排序算法。它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。
5.1 圖解
5.2 代碼實現
package com.data.algorithm.sort;
/**
* 插入排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/6
*/
public class InsertSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for(int i = 0; i < 80000; ++i) {
arr[i] = (int)(Math.random() * 8000000.0D);
}
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
insertSort(arr);
Long endTime = System.currentTimeMillis()- startTime;
System.out.println("排序耗時:" + endTime+"毫秒");
System.out.println("排序耗時:" + endTime/1000+"秒");
}
/**
* 插入排序
* @param arr
*/
public static void insertSort(int[] arr) {
int insertVal ;
int insertIndex;
for(int i = 1; i < arr.length; ++i) {
insertVal = arr[i];
for(insertIndex = i - 1; insertIndex >= 0 && insertVal < arr[insertIndex]; --insertIndex) {
arr[insertIndex + 1] = arr[insertIndex];
}
if (insertIndex + 1 != i) {
arr[insertIndex + 1] = insertVal;
}
}
}
}
6、選擇排序
6.1 代碼實現
package com.data.algorithm.sort;
/**
* 選擇排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/6
*/
public class SelectSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i = 0; i < 80000; ++i) {
arr[i] = (int) (Math.random() * 8000000.0D);
}
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
selectSort(arr);
Long endTime = System.currentTimeMillis() - startTime;
System.out.println("排序耗時:" + endTime + "毫秒");
System.out.println("排序耗時:" + endTime / 1000 + "秒");
}
/**
* 選擇排序
* @param arr
*/
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; ++i) {
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length; ++j) {
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
}
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
}
7、冒泡排序
7.1 代碼實現
package com.data.algorithm.sort;
/**
* 冒泡排序
*
* @author wangjie
* @version V1.0
* @date 2020/3/6
*/
public class BubbleSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for(int i = 0; i < 80000; ++i) {
arr[i] = (int)(Math.random() * 8000000.0D);
}
Long startTime = System.currentTimeMillis();
System.out.println("開始排序");
bubbleSort(arr);
Long endTime = System.currentTimeMillis()- startTime;
System.out.println("排序耗時:" + endTime+"毫秒");
System.out.println("排序耗時:" + endTime/1000+"秒");
}
/**
* 冒泡排序
* @param arr
*/
public static void bubbleSort(int[] arr) {
int temp;
boolean flag = false;
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]) {
flag = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if (!flag) {
break;
}
flag = false;
}
}
}
8、 常用排序算法對比
- 相關術語解釋: