今日分資料結構作業:氣泡排序、堆排、希爾排序、快排……
阿新 • • 發佈:2018-11-11
先看實驗報告:
好吧,這次實驗報告沒有什麼好吐槽的,安安分分的寫了好久。
bug無數,雖然之前寫過,但是沒這麼詳細。
程式碼+註釋:
import java.io.*; import java.util.Arrays; public class Main3 { /*直接排序,希爾排序,氣泡排序,快速排序,直接選擇排序,堆排序,歸併排序演算法 * 直接排序和直接選擇排序不是同一個嗎? * 太虛假了吧 * 既然如此我就寫一個好了 */ static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) { int arr[]=new int[10]; //測試一個1萬資料的陣列 randomArrays(arr); long startTime,endTime; startTime = System.currentTimeMillis(); chooseSort(arr); endTime = System.currentTimeMillis(); System.out.println("選擇排序的時間是:"+(endTime-startTime)+"ms"); upsetArrays(arr); startTime = System.currentTimeMillis(); bubbleSort(arr); endTime = System.currentTimeMillis(); System.out.println("氣泡排序的時間是:"+(endTime-startTime)+"ms"); upsetArrays(arr); startTime = System.currentTimeMillis(); shellSort(arr); endTime = System.currentTimeMillis(); System.out.println("希爾排序的時間是:"+(endTime-startTime)+"ms"); upsetArrays(arr); startTime = System.currentTimeMillis(); memerySort(arr); endTime = System.currentTimeMillis(); System.out.println("歸併排序的時間是:"+(endTime-startTime)+"ms"); upsetArrays(arr); startTime = System.currentTimeMillis(); heapSort(arr); endTime = System.currentTimeMillis(); System.out.println("堆排序的時間是:"+(endTime-startTime)+"ms"); upsetArrays(arr); startTime = System.currentTimeMillis(); quickSort(arr); endTime = System.currentTimeMillis(); System.out.println("快排的時間是:"+(endTime-startTime)+"ms"); upsetArrays(arr); startTime = System.currentTimeMillis(); Arrays.sort(arr); endTime = System.currentTimeMillis(); System.out.println("JAVA類庫自帶快速的時間是:"+(endTime-startTime)+"ms"); } //選擇排序===================================================================================================== /* * 柿子先挑軟的捏,當然要先寫選擇排序 */ static void chooseSort(int arr[]) { for(int i=0;i<arr.length;i++) { for(int j=i+1;j<arr.length;j++) { if(arr[i]>arr[j]) { swap(arr,i,j); } } } } //============================================================================================================ //氣泡排序===================================================================================================== /* * 氣泡排序 * 加個flag優化一下 */ static void bubbleSort(int arr[]) { boolean flag=true; for(int i=0;i<arr.length&&flag;i++) { flag=false; for(int j=arr.length-1;j>i;j--) { if(arr[j]<arr[j-1]) { flag=true; swap(arr,j,j-1); } } } } //============================================================================================================= //希爾排序===================================================================================================== /* * 希爾排序 * 這個排序挺有趣的,剛才看了一個視訊理解了: * https://www.bilibili.com/video/av17062242?from=search&seid=2961680739883013473 * 不過下一個視訊也挺有趣的 * https://www.bilibili.com/video/av17004970/?spm_id_from=trigger_reload * 程式碼我自己實現一下,不行可以除錯,或者看別人的。 * 這個排序不太穩定 * 不過我很奇怪這個原理 */ static void shellSort(int arr[]) { int len=arr.length; int gap=len; //過程增量 do { gap=gap/3+1; for(int i=0;i<len-gap;i++) { if(arr[i]>arr[i+gap]) { int j=i; while(j>=0&&arr[j]>arr[j+gap]) { swap(arr,j,j+gap); j-=gap; } } } } while(gap>1); // 寫下了感覺還是很簡單的,而且測試發現也沒什麼問題。 } //============================================================================================================= //歸併排序===================================================================================================== /* * 歸併排序還是很好用的,很穩定的。 * 記得剛加入ACM的時候,學長就是通過選擇排序和歸併排序給我們講複雜度 * 這個在我大一上學期自己實現了一下,覺得也沒有什麼難度。 * 很經典的分治遞迴 */ static void memerySort(int arr[]) { int[] temp=new int[arr.length]; memerySort(arr,0,arr.length-1,temp); } static void memerySort(int arr[],int l,int r,int temp[]) { int t=(l+r)>>1; //位運算,(x>>1)==x/2。計算比較快,堆排應該會用到比較多的位運算 if(l==r) return; memerySort(arr,l,t,temp); memerySort(arr,t+1,r,temp); memeryArrays(arr,l,r,t,temp); } static void memeryArrays(int arr[],int l,int r,int t,int temp[]) { int i=l,j=t+1; int now=0; while(i<=t&&j<=r) { if(arr[i]<arr[j]) temp[now++]=arr[i++]; else temp[now++]=arr[j++]; } for(;i<=t;i++) { temp[now++]=arr[i]; } for(;j<=r;j++) { temp[now++]=arr[j]; } for(int k=l;k<=r;k++) { arr[k]=temp[k-l]; } } //============================================================================================================= //堆排序======================================================================================================= /* * 堆排這東西,每次都是寫bug10分鐘。debug兩小時。東西太多了,思路太嚴謹了。 * 雖然寫過好幾次吧 * 我本來以為堆排一定要額外開一個堆,沒想到看了網上的思路,不一定是這樣的 * 很節省空間啊 * 大概就是,需要一個adjust函式調整堆(如果要從小排序,需要挑成最大堆) * 把這個無序陣列調整成堆 * 然後把堆頂和陣列最後一個元素交換,堆容量-1 * 這樣每次都把堆裡最大一個元素放到了最後面,就排好序了 * 其實我感覺堆排嚴謹的複雜度應該是n*logn! */ static void heapSort(int[] arr) { buildHeap(arr); //建堆 getSort(arr); //排序 } //需要從下向上調整 static void buildHeap(int[] arr) { for(int i=(arr.length-2)/2;i>=0;i--) { adjustHeap(arr,i,arr.length); } } static void getSort(int[] arr) { for(int i=arr.length-1;i>=1;i--) { swap(arr,0,i); adjustHeap(arr,0,i); } } //i是調整節點為i的點,len是堆容量 static void adjustHeap(int arr[],int i,int len) { while((i<<1|1)<len) { int left=i<<1|1,right=(i<<1)+2; if(right<len&&arr[right]>arr[i]&&arr[right]>arr[left]) { swap(arr,i,right); i=right; } else if(arr[left]>arr[i]) { swap(arr,i,left); i=left; } else break; } } //============================================================================================================= //快排========================================================================================================= /* * 安利一篇文章,挺不錯的 https://mp.weixin.qq.com/s?__biz=MzA5MzY4NTQwMA==&mid=2651005737&idx=1&sn=924250b9065f44f5f 8c7b026ff914fcc&chksm=8bad90debcda19c8fc016c5968d4c817b16c736c0a2c9a5de378ddac1c82b5c4df446 dbeb8e1&mpshare=1&scene=23&srcid=0910GbfDP3XhEWpCqgfK2Ffc#rd */ static void quickSort(int[] arr) { quickSort(arr,0,arr.length-1); } static void quickSort(int[] arr,int l,int r) { if(l>=r) return; int privot=partition(arr,l,r); quickSort(arr,l,privot-1); quickSort(arr,privot+1,r); } static int partition(int[] arr,int start,int end) { int l=start,r=end; int pivot=arr[start]; while(l!=r) { while(l<r&&arr[r]>pivot) { r--; } while(l<r&&arr[l]<=pivot) { l++; } if(l<r) { swap(arr,l,r); } } if(l!=start) swap(arr,l,start); return l; } //============================================================================================================= //列印一個數組,方便測試 static void print(int arr[]) { for(int i=0;i<arr.length;i++) { out.write(arr[i]+" "); } out.write("\n"); out.flush(); } //隨機生成一個數組,方便測試 static void randomArrays(int arr[]) { for(int i=0;i<arr.length;i++) arr[i]=(int) (Math.random()*1000); } //隨機打亂一個數組,方便測試 static void upsetArrays(int[] arr) { for(int i=0;i<arr.length;i++) { int t=(int) (Math.random()*arr.length); if(i!=t) swap(arr,i,t); } } //異或運算交換兩個變數,比較節省時間。 static void swap(int arr[],int a,int b) { arr[a]^=arr[b]; arr[b]^=arr[a]; arr[a]^=arr[b]; } } /* *1000的資料量 *選擇排序的時間是:4ms *氣泡排序的時間是:5ms *希爾排序的時間是:1ms *歸併排序的時間是:1ms *堆排序的時間是:0ms *快排的時間是:1ms *JAVA類庫自帶快速的時間是:1ms *1w的資料量 *選擇排序的時間是:59ms *氣泡排序的時間是:150ms *希爾排序的時間是:3ms *歸併排序的時間是:2ms *堆排序的時間是:3ms *快排的時間是:3ms *JAVA類庫自帶快速的時間是:5ms *5W的資料量 *選擇排序的時間是:1391ms *氣泡排序的時間是:3770ms *希爾排序的時間是:10ms *歸併排序的時間是:11ms *堆排序的時間是:12ms *快排的時間是:20ms *JAVA類庫自帶快速的時間是:9ms *10W的資料量 *選擇排序的時間是:4915ms *氣泡排序的時間是:15191ms *希爾排序的時間是:17ms *歸併排序的時間是:20ms *堆排序的時間是:17ms *快排的時間是:18ms *JAVA類庫自帶快速的時間是:10ms *1千萬的資料,選擇排序和氣泡排序不敢玩了,就搞下這些。 *希爾排序的時間是:1835ms *歸併排序的時間是:1181ms *堆排序的時間是:2030ms *快排的時間是:15282ms *JAVA類庫自帶快速的時間是:500ms *由此可見,陣列的容量越大,差距越大,還是系統自帶的好用,哈哈哈 */