如下如無特殊說明都是按照升序進行排序。 源碼見最下方java
是一種簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,若是他們的順序錯誤就把他們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。這個算法的名字由來是由於越小的元素會經由交換慢慢「浮」到數列的頂端--維基百科。git
冒泡排序很簡單,顧名思義每輪循環中將一個最大/最小的數經過交換一路冒
到數組頂部。github
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {4, 12, 2, 8, 453, 1, 59, 33};
for (int i = 0, length = arr.length; i < arr.length - 1; i++) {
for (int j = 0, tempLength = length - 1 - i; j < tempLength; j++) {
//若是當前數大於下一個數那麼和下一個數交換位置
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
System.out.println(Arrays.toString(arr));
}
}
}
複製代碼
快速排序(Quicksort)是對冒泡排序的一種改進。由 C. A. R. Hoare 在 1960 年提出。它的基本思想是:經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數據都比另一部分的全部數據都要小,而後再按此方法對這兩部分數據分別進行快速排序,整個排序過程能夠遞歸進行,以此達到整個數據變成有序序列--百度百科。算法
public class QuickSort {
private static void deal(Integer[] arr, int start, int end) {
if (start >= end) {
return;
}
int base = arr[start], i = start, j = end;
while (i < j) {
//在右邊找一個比基數小的數,直到i,j相等
while (arr[j] >= base && j > i) {
j--;
}
//在左邊找一個比基數大的數,直到i,j相等
while (arr[i] <= base && j > i) {
i++;
}
//若是ij不相等,交換其值
if (i < j) {
ArrayUtil.swap(arr, i++, j--);
}
}
//此時i等於j,交換基數和i/j,使左邊的數小於等於基數,右邊的數大於等於基數
if (start != i) {
ArrayUtil.swap(arr, start, i);
}
deal(arr, start, i - 1);
deal(arr, j + 1, end);
}
public static void main(String[] args) {
Integer[] arr = {1, 43, 2, 7, 5, 6, 555, 200, 21};
deal(arr, 0, arr.length - 1);
System.out.println("結果" + Arrays.toString(arr));
}
}
複製代碼
是一種簡單直觀的排序算法。它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,一般採用 in-place 排序,於是在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間--維基百科。數組
插入排序的思想很簡單直接:數據結構
動圖以下:ide
public class InsertSort {
public static void sort(Integer[] arr) {
for (int i = 0, length = arr.length; i < length; i++) {
//有序部分從後向前比較,直到找到合適的位置
int j = i, temp = arr[i];
//若是arr[j-1]<=temp,說明arr[j]需爲temp,不然將arr[j-1]向後移動一位
for (; j > 0 && temp < arr[j - 1]; j--) {
arr[j] = arr[j - 1];
}
arr[j] = temp;
System.out.println("當前數組狀態爲:" + Arrays.toString(arr));
}
}
public static void main(String[] args) {
Integer[] arr = {1, 65, 32, 12, 21};
InsertSort.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。希爾排序是非穩定排序算法。動畫
希爾排序是基於插入排序的如下兩點性質而提出改進方法的:ui
public class ShellSort {
public static void sort(Integer[] arr) {
int n1 = arr.length / 2;
// 也可將do/while替換成尾遞歸
do {
//共n1組數據須要進行直接插入排序
for (int start = 0; start < n1; start++) {
//對一組執行插入排序,第一個數爲arr[start],增量爲n1
for (int i = start; i < arr.length; i += n1) {
int j = i, temp = arr[i];
for (; j > start && temp < arr[j - n1]; j -= n1) {
arr[j] = arr[j - n1];
}
arr[j] = temp;
}
}
n1 /= 2;
} while (n1 >= 1);
}
public static void main(String[] args) {
Integer[] arr = {1, 65, 32, 12, 21};
ShellSort.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
是一種簡單直觀的排序算法。它的工做原理以下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。spa
簡單選擇排序顧名思義,每次從無序部分選出一個最大的數,和無序部分的最後一個值交換,重複 n-1 次後全部的值都變成有序狀態.
動畫以下:
public class SimpleSelectSort {
public static void sort(Integer[] arr) {
int length = arr.length;
for (int i = 0; i < length - 1; i++) {
int maxIndex = 0;
for (int j = 1; j < length - i; j++) {
if (arr[j] > arr[maxIndex]) {
maxIndex = j;
}
}
ArrayUtil.swap(arr, maxIndex, length - i);
}
}
public static void main(String[] args) {
Integer[] arr = {1, 65, 32, 12, 21};
sort(arr);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
堆排序(英語:Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆是一個近似徹底二叉樹的結構,並同時知足堆積的性質:即子節點的鍵值或索引老是小於(或者大於)它的父節點。
不瞭解堆
的能夠看看這篇,翻譯的挺好的。
構建大頂堆過程以下:
public class HeapSort {
private static void sort(Integer[] arr) {
int n = arr.length;
//構建大頂堆
for (int i = n / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, n);
}
//排序
for (int i = n - 1; i > 0; i--) {
ArrayUtil.swap(arr, 0, arr[i]);
adjustHeap(arr, 0, i);
}
}
/** * Description: 調整堆 * * @param arr 數組 * @param index 調整index處的對結構 * @param length 堆大小 * @author fanxb * @date 2019/7/31 19:50 */
private static void adjustHeap(Integer[] arr, int index, int length) {
if (index >= length) {
return;
}
int maxIndex = index;
for (int i = 2 * index + 1; i < length - 1 && i <= 2 * index + 2; i++) {
if (arr[maxIndex] < arr[i]) {
maxIndex = i;
}
}
//若是進行了交換,還要調整被交換節點
if (maxIndex != index) {
ArrayUtil.swap(arr, maxIndex, index);
adjustHeap(arr, maxIndex, length);
}
}
public static void main(String[] args) {
Integer[] arr = {1, 65, 32, 334, 12, 21, 65, 112, 444443};
ShellSort.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
歸併排序(英語:Merge sort,或 mergesort),是建立在歸併操做上的一種有效的排序算法,效率爲
。1945 年由約翰·馮·諾伊曼首次提出。該算法是採用分治法(Divide and Conquer)的一個很是典型的應用,且各層分治遞歸能夠同時進行。--維基百科歸併排序的核心思想是將兩個有序的數組合併成一個大的數組,這個過程稱爲 1 次歸併。
一次歸併過程以下(arr1,arr2 兩個有序數組,arr3 存放排序後的數組,i=0,j=0,k=0):
若是arr1[i]<=arr2[j]
,那麼arr3[k]=arr1[i]
,i++,k++
;不然 arr3[k]=arr2[j]
,j++,k++
;
重複 1,直到某個有序數組所有加入到 arr3 中,而後將另一個數組剩餘的部分加到 arr3 中便可。
可是一個無須數組顯然不能直接拆成兩個有序數組,這就須要用到分治
的思想。將數組一層一層的拆分,直到單個數組的長度爲 1(長度爲 1 的數組能夠認爲是有序的),而後再反過來一層層進行歸併操做,那麼最後數組就變成有序的了。
排序過程動圖以下(來自Swfung8):
public class MergeSort {
/** * Description: * * @param arr 待排序數組 * @param start 開始下標 * @param end 結束下標 * @author fanxb * @date 2019/8/6 9:29 */
public static void mergeSort(Integer[] arr, int start, int end) {
if (start >= end) {
return;
}
int half = (start + end) / 2;
//歸併左邊
mergeSort(arr, start, half);
//歸併右邊
mergeSort(arr, half + 1, end);
//合併
merge(arr, start, half, end);
}
/** * Description: * * @param arr arr * @author fanxb * @date 2019/8/5 17:36 */
public static void merge(Integer[] arr, int start, int half, int end) {
ArrayList<Integer> tempList = new ArrayList<>();
int i = start, j = half + 1;
// 循環比較,將較小的放到tempList中
while (i <= half && j <= end) {
if (arr[i] <= arr[j]) {
tempList.add(arr[i]);
i++;
} else {
tempList.add(arr[j]);
j++;
}
}
if (i > half) {
//說明第一個數組已經完了,將第二個數組的剩餘部分放到tempList中
while (j <= end) {
tempList.add(arr[j]);
j++;
}
} else {
//說明第二個數組已經完了,將第一個數組剩餘部分放到tempList中
while (i <= half) {
//說明第二個數組處理完了
tempList.add(arr[i]);
i++;
}
}
//最後將tempList複製到arr中
for (int k = 0, length = tempList.size(); k < length; k++) {
arr[start + k] = tempList.get(k);
}
}
public static void main(String[] args) {
Integer[] arr = {4, 3, 1, 2, 5, 4, 2};
mergeSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
計數排序不以比較爲基礎,核心在於將數 a 存放在 arr[a]上,排序速度超級快,可是要求輸入的數必須是有肯定範圍的整數。
假設對於範圍 0-100 的整數進行排序
public class CountSort {
/** * Description: * * @param arr 待排序數組 * @return void * @author fanxb * @date 2019/8/6 17:36 */
public static void sort(Integer[] arr, Integer minValue, Integer maxValue) {
int range = maxValue - minValue + 1;
Integer[] numCount = new Integer[range];
Arrays.fill(numCount, 0);
for (Integer item : arr) {
item = item - minValue;
numCount[item]++;
}
int count = 0;
for (int i = 0; i < range; i++) {
if (numCount[i] == 0) {
continue;
}
for (int j = 0; j < numCount[i]; j++) {
arr[count] = minValue + i;
count++;
}
}
}
public static void main(String[] args) {
Integer[] arr = {1, 65, 32, 334, 12, 21, 65, 112, 444443};
sort(arr, 1, 444443);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
PS
計數排序有不少的變種,下面列舉幾種:
很簡單,先進行一次遍歷將正數負數分開,在分別進行排序,負數取反後再排。
這裏能夠利用文件來實現。先將超大的數組按照規則分紅幾個部分,分別存到文件中(好比 1-1000000 放在文件 1 中,1000001-2000000 放在文件 2 中,以此類推)就將超大的數組分紅了小的數組,而後再分別計數排序便可。
是一種非比較型整數排序算法,其原理是將整數按位數切割成不一樣的數字,而後按每一個位數分別比較。因爲整數也能夠表達字符串(好比名字或日期)和特定格式的浮點數,因此基數排序也不是隻能使用於整數。基數排序的發明能夠追溯到 1887 年赫爾曼·何樂禮在打孔卡片製表機(Tabulation Machine)上的貢獻。--來自維基百科
基數排序能夠採用 LSD(從高位開始),MSD(從低位開始),這裏以 MSD 爲例。
(有興趣的能夠思考思考如何用 LSD 實現,目前網上絕大多數都是 MSD 實現的)
爲何可以這樣排序呢?第一遍排序完畢後,全部的數是按照個位排序的,對於全部小於 10 的數來講,他們已是相對有序(並非說位置再也不變化,只是相對順序再也不變化)的了,在第二輪對十位排序時,全部的個位數都將被放到 0 桶了,用先進先出策略處理這些個位數,取出時個位數仍是有序的。
第二輪排序後全部小於 10 的數的位置已經肯定且再也不變化,大於 10 小於 100 的數的位置已經相對有序.在第三輪中全部小於 100 的數都將被放到 0 桶,這時相對有序就變成了絕對的了,取出後位置再也不變化。
第三輪排序後全部小於 100 的數的位置已經肯定且再也不變化。以此類推直到所有排序完成。
動圖以下:
public class RadixSort {
@SuppressWarnings("unchecked")
public static void sort(Integer[] arr) {
//定義桶
LinkedList<Integer>[] buckets = new LinkedList[10];
for (int i = 0; i < 10; i++) {
buckets[i] = new LinkedList<>();
}
int size = arr.length;
//當前處理第幾位的數
int count = 0;
while (true) {
//是否繼續進位
boolean isContinue = false;
//將數放到桶中
for (int i = 0; i < size; i++) {
int temp = arr[i] / (int) Math.pow(10, count) % 10;
if (!isContinue && temp != 0) {
// 若是存在一個數取的值不爲0,說明還要繼續循環。
isContinue = true;
}
buckets[temp].addLast(arr[i]);
}
if (!isContinue) {
return;
}
//從桶中取出放到arr中,注意以什麼順序放進去的就要以什麼順序取出來(先進先出)
int index = 0;
for (int i = 0; i < 10; i++) {
Integer item;
while ((item = buckets[i].pollFirst()) != null) {
arr[index++] = item;
}
}
//位數+1
count++;
}
}
public static void main(String[] args) {
Integer[] arr = {4, 31, 1, 29, 5, 4, 2};
sort(arr);
System.out.println(Arrays.toString(arr));
}
}
複製代碼
本文原創發佈於:www.tapme.top/blog/detail…
源碼:github