幾種排序演算法的原理以及 Java 實現
所謂排序,就是使一串記錄,按照其中的某個或某些關鍵字的大小,遞增或遞減的排列起來的操作。排序演算法,就是如何使得記錄按照要求排列的方法。排序演算法在很多領域得到相當地重視,尤其是在大量資料的處理方面。 |
本文給出常見的幾種排序演算法的原理以及 Java 實現,包括常見的簡單排序和高階排序演算法,以及其他常用的演算法知識。
- 簡單排序:氣泡排序、選擇排序、插入排序
- 高階排序:快速排序、歸併排序、希爾排序
- 相關演算法知識:劃分、遞迴、二分查詢
- 從第一個資料開始,與第二個資料相比較,如果第二個資料小於第一個資料,則交換兩個資料的位置。
- 指標由第一個資料移向第二個資料,第二個資料與第三個資料相比較,如果第三個資料小於第二個資料,則交換兩個資料的位置。
- 依此類推,完成第一輪排序。第一輪排序結束後,最大的元素被移到了最右面。
- 依照上面的過程進行第二輪排序,將第二大的排在倒數第二的位置。
- 重複上述過程,沒排完一輪,比較次數就減少一次。
待排序資料:7, 6, 9, 8, 5,1
第一輪排序過程:
指標先指向7,7和6比較,6<7,交換6和7的位置,結果為:6,7,9,8,5,1 指標指向第二個元素7,7和9比較,9>7,不用交換位置,結果仍為:6,7,9,8,5,1 指標指向第三個元素9,比較9和8,8<9,交換8和9的位置,結果為:6,7,8,9,5,1 指標指向第四個元素9,比較9和5,5<9,交換5和9,結果為:6,7,8,5,9,1 指標指向第五個元素9,比較9和1,1<9,交換1和9的位置,結果為6,7,8,5,1,9
第一輪排序結束後,最大的數字9被移到了最右邊。
進行第二輪排序,過程同上,只是由於最大的9已經放在最右邊了,因此不用在比較9了,少了一次比較,第二輪結束的結果為:6,7,5,1,8,9
第三輪結果:6,5,1,7,8,9
第四輪比較結果:5,1,6,7,8,9
第五輪比較結果:1,5,6,7,8,9
最終排序結果為:1,5,6,7,8,9,由上可知N個資料排序,需要進行N-1輪排序;第i輪排序需要的比較次數為N-i次。
需要兩層迴圈,第一層迴圈i表示排序的輪數,第二層迴圈j表示比較的次數。
例項
package com.test.insertsort;/** * 選擇排序 * @author Administrator * */public class ChooseSort { private int[] array; private int length; public ChooseSort(int[] array){ this.array = array; this.length = array.length; } /** * 列印陣列中的所有元素 */ public void display(){ for(int i: array){ System.out.print(i+" "); } System.out.println(); } /** * 選擇排序演算法 */ public void chooseSort(){ for(int i=0; i<length-1; i++){ int minIndex = i; for(int j=minIndex+1;j<length;j++){ if(array[j]<array[minIndex]){ minIndex = j; } } int temp = array[i]; array[i] = array[minIndex]; array[minIndex] = temp; } } public static void main(String[] args){ int[] array={100,45,36,21,17,13,7}; ChooseSort cs = new ChooseSort(array); System.out.println("排序前的資料為:"); cs.display(); cs.chooseSort(); System.out.println("排序後的資料為:"); cs.display(); }}
插入排序是簡單排序中最快的排序演算法,雖然時間複雜度仍然為O(n*n),但是卻比氣泡排序和選擇排序快很多。
待比較資料:7, 6, 9, 8, 5,1
需要兩層迴圈,第一層迴圈index表示上述例子中的指標,即遍歷從座標為1開始的每一個元素;第二層迴圈從leftindex=index-1開始,leftindex--向左遍歷,將每一個元素與i處的元素比較,直到j處的元素小於i出的元素或者leftindex<0;遍歷從i到j的每一個元素使其右移,最後將index處的元素放到leftindex處的空位處。
例項
package com.test.insertsort;/** * 插入排序演算法: * 1、以陣列的某一位作為分隔位,比如index=1,假設左面的都是有序的. * * 2、將index位的資料拿出來,放到臨時變數裡,這時index位置就空出來了. * * 3、從leftindex=index-1開始將左面的資料與當前index位的資料(即temp)進行比較,如果array[leftindex]>temp, * 則將array[leftindex]後移一位,即array[leftindex+1]=array[leftindex],此時leftindex就空出來了. * * 4、再用index-2(即leftindex=leftindex-1)位的資料和temp比,重複步驟3, * 直到找到<=temp的資料或者比到了最左面(說明temp最小),停止比較,將temp放在當前空的位置上. * * 5、index向後挪1,即index=index+1,temp=array[index],重複步驟2-4,直到index=array.length,排序結束, * 此時陣列中的資料即為從小到大的順序. * * @author bjh * */public class InsertSort { private int[] array; private int length; public InsertSort(int[] array){ this.array = array; this.length = array.length; } public void display(){ for(int a: array){ System.out.print(a+" "); } System.out.println(); } /** * 插入排序方法 */ public void doInsertSort(){ for(int index = 1; index<length; index++){//外層向右的index,即作為比較物件的資料的index int temp = array[index];//用作比較的資料 int leftindex = index-1; while(leftindex>=0 && array[leftindex]>temp){//當比到最左邊或者遇到比temp小的資料時,結束迴圈 array[leftindex+1] = array[leftindex]; leftindex--; } array[leftindex+1] = temp;//把temp放到空位上 } } public static void main(String[] args){ int[] array = {38,65,97,76,13,27,49}; InsertSort is = new InsertSort(array); System.out.println("排序前的資料為:"); is.display(); is.doInsertSort(); System.out.println("排序後的資料為:"); is.display(); }}
時間複雜度,由於仍然需要兩層迴圈,插入排序的時間複雜度仍然為O(n*n)。
比較次數:在第一輪排序中,插入排序最多比較一次;在第二輪排序中插入排序最多比較二次;以此類推,最後一輪排序時,最多比較N-1次,因此插入排序的最多比較次數為1+2+...+N-1=N*(N-1)/2。儘管如此,實際上插入排序很少會真的比較這麼多次,因為一旦發現左側有比目標元素小的元素,比較就停止了,因此,插入排序平均比較次數為N*(N-1)/4。
移動次數:插入排序的移動次數與比較次數幾乎一致,但移動的速度要比交換的速度快得多。
綜上,插入排序的速度約比氣泡排序快一倍(比較次數少一倍),比選擇排序還要快一些,對於基本有序的資料,插入排序的速度會很快,是簡單排序中效率最高的排序演算法。
上文介紹了常見簡單演算法:氣泡排序、選擇排序和插入排序。本文介紹高階排序演算法:快速排序和歸併排序。在開始介紹演算法之前,首先介紹高階演算法所需要的基礎知識:劃分、遞迴,並順帶介紹二分查詢演算法。
劃分是快速排序的前提,即把資料分為兩組,大於特定值的資料在一組,小於特定值的資料在另一組。快速排序即是由劃分和遞迴操作來完成的。
(1)原理:
定義一個閾值,分別從最左面和最右面向中間遍歷元素,左面找到一個大於閾值的資料便停止,右邊找到一個小於閾值的資料便停止,如果此時左右兩邊都還沒有走到中間,則交換左面大於閾值的資料和右面小於閾值的資料;重複上述過程,直到左面指標和右面指標相遇,此時左面資料均小於閾值,右面資料均大於閾值,劃分結束。劃分結束後,資料仍然是無序的,但更接近於有序。
(2)例子:
待劃分資料:7, 6, 9, 8, 5,1,假設閾值為5
第一輪:左指標指向7,右指標指向1,左指標向後移,右指標向左移,發現左面第一個大於5的元素7,右面第一個小於5的元素1,交換7和1的位置,結果:1,6,9,8,5,7;
第二輪:從6開始找大於5的數字,找到6,右邊從5起找小於5的數字,找到1,但此時由於6在1的右面,,即右指標<左指標,左右指標交叉,此時劃分結束。原數列被劃分為兩部分,左側子數列只有一個元素,即為1,其為小於閾值的子數列;右側子數列包括5個元素,均為大於閾值5的元素。 (3)程式碼實現:
例項
package com.test.insertsort; /** * 劃分、遞迴、快排 * @author bjh * */public class QuickSort { /**待排序、劃分陣列*/ private int[] array; /**陣列長度*/ private int length; public QuickSort(int[] array){ this.array = array; this.length = array.length; } /** * 列印元素 */ public void printArray(){ for(int i=0; i<length; i++){ System.out.print(array[i]+" "); } System.out.println(); } /** * 劃分 * @return 劃分的分界點 */ public int partition(int left, int right, int pivot){ //左指標的起點,left-1是由於在後面的迴圈中,每迴圈一次左指標都要右移, //這樣可以確保左指標從左邊第一個元素開始,不然是從第二個開始 int leftpoint = left-1; //右指標的起點,right+1是由於後面的迴圈中,每迴圈一次右指標都要左移, //這樣可以確保右指標從最右邊開始,不然是從倒數第二個開始 int rightpoint = right+1; while(true){ //找到左邊大於pivot的資料,或者走到了最右邊仍然沒有找到比pivot大的資料 while(leftpoint<right && array[++leftpoint]<pivot); //找到右邊小於pivot的資料,或者走到了最左邊仍然沒有找到比pivot小的資料 while(rightpoint>left && array[--rightpoint]>pivot); //左指標和右指標重疊或相交 if(leftpoint >= rightpoint){ break; }else{ //交換左邊大的和右邊小的資料 swap(leftpoint,rightpoint); } } //返回分界點,即右邊子陣列中最左邊的點 return leftpoint; } /** * 交換資料 */ public void swap(int leftpoint,int rightpoint){ int temp = array[leftpoint]; array[leftpoint] = array[rightpoint]; array[rightpoint] = temp; } public static void main(String args[]){ int[] array = {99,78,26,17,82,36,9,81,22,100,30,20,17,85}; QuickSort qs = new QuickSort(array); System.out.println("劃分前的資料為:"); qs.printArray(); int bound = qs.partition(0, array.length-1, 50); System.out.println("劃分後的資料為:"); qs.printArray(); System.out.println("劃分的分界點為:" + array[bound] + ",分界點的座標為:" + bound); } }
執行結果為:
原文地址:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2689648/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- C#常用8種排序演算法實現以及原理簡介C#排序演算法
- 面試必備:八種排序演算法原理及Java實現面試排序演算法Java
- 幾種常用的排序演算法之JavaScript實現排序演算法JavaScript
- 六種排序演算法的JavaScript實現以及總結排序演算法JavaScript
- 用 Java 實現的八種常用排序演算法Java排序演算法
- 【演算法】Java實現七種常用排序演算法演算法Java排序
- python3實現幾種常見的排序演算法Python排序演算法
- **超詳細的**10種排序演算法原理及 JS 實現排序演算法JS
- Android的延遲實現的幾種解決方案以及原理分析Android
- 幾種常用的排序演算法排序演算法
- 快速掌握Java幾種排序演算法的區別與排序演算法的應用Java排序演算法
- 排序演算法:Java實現希爾排序排序演算法Java
- 排序演算法 Java實現排序演算法Java
- 排序演算法Java實現排序演算法Java
- 幾種經典的排序演算法排序演算法
- 九種排序演算法的 JavaScript 實現排序演算法JavaScript
- JavaScript實現的7種排序演算法JavaScript排序演算法
- 負載均衡的幾種演算法Java實現程式碼負載演算法Java
- 排序演算法-Java實現快速排序演算法排序演算法Java
- 用 Java 實現常見的 8 種內部排序演算法Java排序演算法
- js實現兩種實用的排序演算法——冒泡、快速排序JS排序演算法
- php實現4種排序演算法PHP排序演算法
- 三種快速排序演算法以及快速排序的優化排序演算法優化
- 簡述幾種常用的排序演算法排序演算法
- java單例的幾種實現方法Java單例
- java幾種代理模式的實現方式Java模式
- 實現繼承的幾種方式及工作原理繼承
- python實現氣泡排序、插入排序以及快速排序演算法Python排序演算法
- PHP實現四種基本排序演算法PHP排序演算法
- 各種排序演算法思想複雜度及其java程式實現排序演算法複雜度Java
- 35.幾種常見的排序演算法排序演算法
- 幾種常見的排序演算法總結排序演算法
- java氣泡排序演算法實現Java排序演算法
- 10大排序演算法——Java實現排序演算法Java
- 常用的排序演算法(五)--選擇排序以及最佳化(PHP實現)排序演算法PHP
- 幾種機器學習演算法的偏差以及防範機器學習演算法
- 幾種簡單的負載均衡演算法及其Java程式碼實現負載演算法Java
- Swift實現八種經典排序演算法Swift排序演算法