排序演算法(Java實現),排序演算法java實現
這幾天一直在看嚴蔚敏老師的那本《資料結構》那本書。之前第一次學懵懵逼逼,當再次看的時候,發覺寫的是非常詳細,非常的好。
那就把相關的排序演算法用我熟悉的Java語言記錄下來了。以下排序演算法是我認為比較重要的,而且在面試中比較容易考的演算法。
(一)前言
排序其實是一個相當大的概念,主要分為兩類:內部排序和外部排序。而我們通常所說的各種排序演算法其實指的是內部排序演算法。內部排序是基於記憶體的,整個排序過程都是在記憶體中完成的,而外部排序指的是由於資料量太大,記憶體不能完全容納,排序的時候需要藉助外存才能完成(常常是算計著某一部分已經計算過的資料移出記憶體讓另一部分未被計算的資料進入記憶體)。而我們本篇文章將主要介紹內排序中的幾種常用排序演算法:
(二)冒泡排序
最經典的排序方法,沒有之一,所有人學排序的第一個演算法。
比較簡單直接看代碼吧。
1 public class Main { 2 public static void main(String[] args) { 3 4 int[] a = {7, 6, 9, 3, 2, 11, 9}; 5 Bubble b = new Bubble(); 6 b.bubbleSort(a); 7 for (int i = 0; i < a.length; i++) { 8 System.out.print(a[i] + " "); 9 }10 System.out.println();11 }12 }13 14 class Bubble {15 16 int[] bubbleSort(int[] a) {17 for (int i = 0; i < a.length - 1; i++) {18 for (int j = i + 1; j < a.length; j++) {19 if (a[i] > a[j]) {20 swap(a, i, j);21 }22 }23 }24 return a;25 }26 27 void swap(int[] a, int i, int j) {28 int t = 0;29 t = a[i];30 a[i] = a[j];31 a[j] = t;32 }33 }
(三)快速排序
史上最快的排序演算法之一,稱為快速排序。連Arrays.sort底層都是快速排序,不過有進行改進(DualPivotQuicksort三千多行代碼,向大神跪了)
快速排序的基本思想是,從序列中任選一個元素,但通常會直接選擇序列的第一個元素作為一個標準,所有比該元素值小的元素全部移動到他的左邊,比他大的都移動到他的右邊。我們稱這叫做一趟快速排序,位於該元素兩邊的子表繼續進行快速排序演算法直到整個序列都有序。該排序演算法是目前為止,內部排序中效率最高的排序演算法。具體它是怎麼做的呢?
首先他定義了兩個頭尾指標,分別指向序列的頭部和尾部。從high指標位置開始掃描整個序列,如果high指標所指向的元素值大於等於臨界值,指標前移。如果high指標所指向的元素的值小於臨界值的話:
將high指標所指向的較小的值交換給low指標所指向的元素值,然後low指標前移。
然後重複上述過程,直至x=48左邊全部小於他,右邊全部大於他。看代碼
1 class Quick { 2 3 int[] quickSort(int[] a, int left, int right) { 4 5 if (left < right) { 6 int pos = postion(a, left, right); 7 quickSort(a, left, pos - 1); 8 quickSort(a, pos + 1, right); 9 }10 return a;11 }12 13 int postion(int[] a, int left, int right) {14 15 int t = a[left];16 while (left < right) {17 while (left < right && t <= a[right]) --right;18 a[left] = a[right];19 while (left < right && t >= a[left]) ++left;20 a[right] = a[left];21 }22 a[left] = t;23 return left;24 }25 26 }
(四)堆排序
先瞭解下什麼叫做堆。
堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。
大根堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小根堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
同時,我們對堆中的結點按層進行編號,將這種邏輯結構映射到數組中就是下面這個樣子
堆排序我自認為理解了,但寫起部落格有些麻煩,大家想要瞭解可以去 這裡看看 堆排序演算法,我覺的寫的挺好的
我這裡直接用PriorityQueue
1 class Heap { 2 3 int[] heapSort(int[] a) { 4 5 int[] t = new int[a.length]; 6 PriorityQueue<Integer> pq = new PriorityQueue<>(a.length); 7 //建堆 8 for (int i = 0; i < a.length; i++) { 9 pq.add(a[i]);10 }11 int cnt = 0;12 //出堆後破壞了堆的定義,那就調整堆13 while (!pq.isEmpty()) {14 t[cnt++] = pq.poll();15 }16 return t;17 }18 }
(五)歸併排序
這裡的歸併類排序演算法指的就是歸併排序。歸併排序的核心思想是,對於一個初始的序列不斷遞迴,直到子序列中的元素足夠少時,對他們進行直接排序。然後遞迴返回繼續對兩個分別有序的序列進行直接排序,最終遞迴結束的時候,整個序列必然是有序的。就是分而治之
1 /*歸併排序的遞迴調用*/ 2 public static void MergeSort(int[] array,int low,int high){ 3 if(low == high){ 4 //說明子數組長度為1,無需分解,直接返回即可 5 }else{ 6 int p = (low+high)/2; 7 MergeSort(array,low,p); 8 MergeSort(array,p+1,high); 9 //完成相鄰兩個子集合的歸併10 MergeTwoData(array,low,high);11 }12 }13 /*用於排序兩個子序列的歸併排序演算法實現*/14 public static void MergeTwoData(int[] array,int low,int high){ 15 int[] arrCopy = new int[high-low+1];16 int i,j;17 i = low;j= (low+high)/2+1;18 for (int key=0;key<=high-low;key++){19 //如果左邊子數組長度小於右邊數組長度,當左數組全部入庫之後,右側數組不用做比較直接入庫20 if(i==(low+high)/2+1){21 arrCopy[key] = array[j];22 j++;23 }24 //如果右側數組長度小於左側數組長度,當右側數組全部入庫之後,左側數組不用做比較直接入庫25 else if(j==high+1){26 arrCopy[key]=array[i];27 i++;28 }else if(array[i]<array[j]){29 arrCopy[key]=array[i];30 i++;31 }else{32 arrCopy[key] = array[j];33 j++;34 }35 }36 j = 0;37 //按順序寫回原數組38 for(int x=low;x<=high;x++) {39 array[x] = arrCopy[j];40 j++;41 }42 }