本篇文章僅作為編程語言學(xué)習(xí)的參考案例, 幫助理解排序算法的實(shí)現(xiàn)邏輯, 如有意見或建議請(qǐng)留言.
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@Description: 排序案例
@ProjectName: helloworld
-
@ClassName: OrderTest
*/
public class OrderSortTest {/**
- @description 每次冒泡過程都是從數(shù)列的第一個(gè)元素開始,然后依次和剩
余的元素進(jìn)行比較,若小于相鄰元素,則交換兩者位置, - 同時(shí)將較大元素作為下一個(gè)比較的基準(zhǔn)元素,繼續(xù)將該元素與其相鄰的元素
進(jìn)行比較,直到數(shù)列的最后一個(gè)元素 - @param arr
*/
public static void maopaoSort(int[] arr) {
// 第一層for循環(huán),用來控制冒泡的次數(shù)
for (int i = 1; i < arr.length; i++) {
// 第二層for循環(huán),用來控制冒泡一層層到最后
for (int j = 0; j < arr.length - 1; j++) {
// 如果前一個(gè)數(shù)比后一個(gè)數(shù)大,兩者調(diào)換 ,意味著泡泡向上走了一層
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
- @description 第一點(diǎn)是加入了一個(gè)布爾值,判斷第二層循環(huán)中的調(diào)換有沒有
執(zhí)行,如果沒有進(jìn)行兩兩調(diào)換,說明后面都已經(jīng)排好序了, - 已經(jīng)不需要再循環(huán)了,直接跳出循環(huán),排序結(jié)束.第二點(diǎn)是第二層循環(huán)不再
循環(huán) 到arr.length - 1,因?yàn)橥饷娴膇循環(huán)遞增一次, - 說明數(shù)組最后就多了一個(gè)排好序的大泡泡.第二層循環(huán)也就不需要到最末尾
一位了,可以提前結(jié)束循環(huán) - @param arr
*/
public static void maopaoSortPlus(int[] arr) {
if (arr != null && arr.length > 1) {
for (int i = 0; i < arr.length - 1; i++) {
// 初始化一個(gè)布爾值
boolean flag = true;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 調(diào)換
int temp;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
// 改變flag
flag = false;
}
}
if (flag) {
break;
}
}
}
}
/**
- @description 一次插入排序的操作過程:將待插元素,依次與已排序好的
子數(shù)列元素從后到前進(jìn)行比較,如果當(dāng)前元素值比待插元素值大, - 則將移位到與其相鄰的后一個(gè)位置,否則直接將待插元素插入當(dāng)前元素相
鄰的后一位置,因?yàn)檎f明已經(jīng)找到插入點(diǎn)的最終位置 - @param arr
*/
public static void insertSort(int[] arr) {
if (arr.length >= 2) {
for (int i = 1; i < arr.length; i++) {
// 挖出一個(gè)要用來插入的值,同時(shí)位置上留下一個(gè)可以存新的值的坑
int x = arr[i];
int j = i - 1;
// 在前面有一個(gè)或連續(xù)多個(gè)值比x大的時(shí)候,一直循環(huán)往前面找,
// 將x插入到這串值前面
while (j >= 0 && arr[j] > x) {
// 當(dāng)arr[j]比x大的時(shí)候,將j向后移一位,正好填到坑中
arr[j + 1] = arr[j];
j--;
}
// 將x插入到最前面
arr[j + 1] = x;
}
}
}
/**
- @description 選擇待排數(shù)列的首部第一個(gè)元素為基準(zhǔn)元素,設(shè)置兩指針,
分別指向數(shù)列首尾部位置,假設(shè)兩指針分別設(shè)為i和j。每次遍歷的過程是這
樣的,首先遍歷指針j所指向的元素,直到j(luò)指向的元素值小于基準(zhǔn)元素時(shí),
停止遍歷,將其與指針i所指向的元素進(jìn)行交換,因?yàn)楫?dāng)前指針?biāo)肝恢镁褪?br> 用于插入較基準(zhǔn)元素小的元素, 然后再將指針i加一。接著輪到指針i遍歷,直
到i所指向的元素值大于基準(zhǔn)元素時(shí),停止遍歷,將其與指針j所指向的元素
進(jìn)行交換,之所以可以交換, 是因?yàn)橹羔榡所指向的元素剛剛已經(jīng)交換到前
半部分呢,故可以直接選擇覆蓋就行,這樣就將大于基準(zhǔn)元素的元素放于后
半部分。依此類推,直到指針i與指針相等或者大于時(shí),停止外部循環(huán)。最后
直接將基準(zhǔn)元素直接放置于指針i所指向的位置即可,完成分區(qū)操作。 - @param arr
- @param begin
- @param end
*/
public static void quickSort(int[] arr, int begin, int end) {
// 先定義兩個(gè)參數(shù)接收排序起始值和結(jié)束值
int a = begin;
int b = end;
// 先判斷a是否大于b
if (a >= b) {
// 沒必要排序
return;
}
// 基準(zhǔn)數(shù),默認(rèn)設(shè)置為第一個(gè)值
int x = arr[a];
// 循環(huán)
while (a < b) {
// 從后往前找,找到一個(gè)比基準(zhǔn)數(shù)x小的值,賦給arr[a]
// 如果a和b的邏輯正確--a<b ,并且最后一個(gè)值arr[b]>x,就一直往下找,直到找到后面的值大于x
while (a < b && arr[b] >= x) {
b--;
}
// 跳出循環(huán),兩種情況,一是a和b的邏輯不對(duì)了,a>=b,這時(shí)候排序結(jié)束.二是在后面找到了比x小的值
if (a < b) {
// 將這時(shí)候找到的arr[b]放到最前面arr[a]
arr[a] = arr[b];
// 排序的起始位置后移一位
a++;
}
// 從前往后找,找到一個(gè)比基準(zhǔn)數(shù)x大的值,放在最后面arr[b]
while (a < b && arr[a] <= x) {
a++;
}
if (a < b) {
arr[b] = arr[a];
// 排序的終止位置前移一位
b--;
}
}
// 跳出循環(huán) a < b的邏輯不成立了,a==b重合了,此時(shí)將x賦值回去arr[a]
arr[a] = x;
// 調(diào)用遞歸函數(shù),再細(xì)分再排序
quickSort(arr, begin, a - 1);
quickSort(arr, a + 1, end);
}
/**
- @description 選擇排序也是一種簡單直觀的排序算法,實(shí)現(xiàn)原理比較直觀
易懂:首先在未排序數(shù)列中找到最小元素, 然后將其與數(shù)列的首部元素進(jìn)
行交換,然后,在剩余未排序元素中繼續(xù)找出最小元素,將其與已排序數(shù)列
的末尾位置元素交換。 以此類推,直至所有元素圴排序完畢 - @param arr
*/
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int min = i; // 遍歷的區(qū)間最小的值
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[min]) {
// 找到當(dāng)前遍歷區(qū)間最小的值的索引
min = j;
}
}
if (min != i) {
// 發(fā)生了調(diào)換
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
}
/**
- @description 歸并排序,簡單的說把一串?dāng)?shù),從中平等分為兩份,再把兩份再細(xì)
分,直到不能細(xì)分為止,這就是分而治之的分的步驟. 再從最小的單元,兩兩合
并,合并的規(guī)則是將其按從小到大的順序放到一個(gè)臨時(shí)數(shù)組中,再把這個(gè)臨時(shí)
數(shù)組替換原數(shù)組相應(yīng)位置,這就是治 - @param a
- @param s
- @param m
- @param e
*/
private static void merge(int[] a, int s, int m, int e) {
// 初始化一個(gè)從起始s到終止e的一個(gè)數(shù)組
int[] temp = new int[(e - s) + 1];
// 左起始指針
int l = s;
// 右起始指針
int r = m + 1;
int i = 0;
// 將s-e這段數(shù)據(jù)在邏輯上一分為二,l-m為一個(gè)左邊的數(shù)組,r-e為一個(gè)右邊的數(shù)組,兩邊都是有序的
// 從兩邊的第一個(gè)指針開始遍歷,將其中小的那個(gè)值放在temp數(shù)組中
while (l <= m && r <= e) {
if (a[l] < a[r]) {
temp[i++] = a[l++];
} else {
temp[i++] = a[r++];
}
}
// 將兩個(gè)數(shù)組剩余的數(shù)放到temp中
while (l <= m) {
temp[i++] = a[l++];
}
while (r <= e) {
temp[i++] = a[r++];
}
// 將temp數(shù)組覆蓋原數(shù)組
for (int n = 0; n < temp.length; n++) {
a[s + n] = temp[n];
}
}
/**
- @description 歸并排序
- @param a
- @param s
- @param e
*/
public static void mergeSort(int[] a, int s, int e) {
int m = (s + e) / 2;
if (s < e) {
mergeSort(a, s, m);
mergeSort(a, m + 1, e);
// 歸并
merge(a, s, m, e);
}
}
/**
- 獲取一個(gè)打亂的數(shù)組
- @param arr
*/
private static int[] getRandomArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
arr[i] = new Random().nextInt(arr.length);
}
return arr;
}
/**
@description 測試
-
@param args
*/
public static void main(String[] args) {
int[] arr = new int[200000];
int[] a = getRandomArr(arr);
int[] b = a.clone();
int[] c = b.clone();
int[] d = b.clone();
int[] e = b.clone();
int[] f = b.clone();long s = System.currentTimeMillis();
quickSort(a, 0, a.length - 1);
System.out.println("快速排序耗時(shí): " + (System.currentTimeMillis() - s) + " 毫秒");long s = System.currentTimeMillis();mergeSort(d, 0, d.length - 1);
System.out.println("歸并排序耗時(shí): " + (System.currentTimeMillis() - s) + " 毫秒");s = System.currentTimeMillis();selectSort(b);
System.out.println("選擇排序耗時(shí): " + (System.currentTimeMillis() - s) + " 毫秒");s = System.currentTimeMillis();
insertSort(c);
System.out.println("插入排序耗時(shí): " + (System.currentTimeMillis() - s) + " 毫秒");s = System.currentTimeMillis();
maopaoSortPlus(e);
System.out.println("冒泡增強(qiáng)耗時(shí): " + (System.currentTimeMillis() - s) + " 毫秒");s = System.currentTimeMillis();
maopaoSort(f);
System.out.println("冒泡排序耗時(shí): " + (System.currentTimeMillis() - s) + " 毫秒");// 輸出結(jié)果, 查看是否正確
/for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + ",");
}
System.out.println("");
for (int i = 0; i < a.length; i++) {
System.out.print(b[i] + ",");
}
System.out.println("");
for (int i = 0; i < a.length; i++) {
System.out.print(c[i] + ",");
}
System.out.println("");
for (int i = 0; i < a.length; i++) {
System.out.print(d[i] + ",");
}
System.out.println("");
for (int i = 0; i < a.length; i++) {
System.out.print(e[i] + ",");
}
System.out.println("");
for (int i = 0; i < a.length; i++) {
System.out.print(f[i] + ",");
}/
}
}
- @description 每次冒泡過程都是從數(shù)列的第一個(gè)元素開始,然后依次和剩