java 交換排序之(冒泡排序、快速排序)

2016年上班第一天,閒來無事,先寫篇博文來結束今天。我們大家都知道java的排序算法很多,接下來我就先看看java最常用的幾種排序算法的思想源碼附上。(本文所有排序只針對值排序,關於對象排序問題待續.....)

1.插入排序(直接插入排序、二分法插入排序、表插入排序、shell排序)

2.選擇排序(直接選擇排序、堆排序)

3.交換排序(冒泡排序、快速排序)

4.分配排序(基數排序)

5.歸併排序(內排序、外排序)


一、java冒泡排序實現(大家最喜歡也是最簡單的排序算法,但是性能不是那麼ok 當排序數組很大是性能就很低了)

冒泡排序算法實現思想:

    //算法分析:

    一次比較相鄰的兩個數,將大數放在前面、小數放在後面(小數放在前面、大數放在後面)。首先比較第一個和第二     個,滿足條件互換位置。然後第二個和第三個比較。直到倒數第二個和最後一個比較。得到一個最大或者最小的數放    在最後完成第一輪比較。一次進行第二輪比較、第三輪直到結束。

   //冒泡排序算法:(實現源碼)

    public static void maopaoSort(int[] arr){
            int temp;
            for(int i = 0;i < arr.length; i++){
                for(int j = 0; j < arr.length-1-i; j++ ){
                    if(arr[j] < arr[j+1]){
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
    }

二、java交換排序之快速排序

    //算法分析:

    快速排序是C.R.A.Hoare於1962年提出的一種劃分交換排序。它採用了一種分治的策略,通常稱其爲分治法(Divide-and-ConquerMethod)。

(1) 分治法的基本思想
     分治法的基本思想是:將原問題分解爲若干個規模更小但結構與原問題相似的子問題。遞歸地解這些子問題,然後將這些子問題的解組合爲原問題的解。

(2) 實例分解

    快速排序是對冒泡排序的一種該進(兩種排序都是屬於交換排序),通過一趟排序將原有的排序數組分成獨立的兩個部分。其中一部分的數據比另外一部分的數據都要小。然後再按照此方法對剛劃分的兩部分進行同樣的分割。以此達到整個數組變成有序的序列。

    假設需要排序的數組是A[0]......A[N-1],首先任意選取一個數據(通常選擇A[0])作爲關鍵數據然後把所有比它小的數都放在前面,所有比它大的數都放在它後面。這整個過程稱爲一趟快速排序(因此我們可以把一趟快速排序寫成一個獨立的方法。方便重複調用)

    (1)設置兩個變量i,j,排序開始的時候i=0,j=N-1.

    (2)以第一個數據A[0]作爲關鍵數據,賦值給key,即key=A[i]。

    (3)從j(j = j-1 )開始向前搜索,找到第一個小於key的值,讓該值與key進行交換。

    (4)從i(i = i+1)開始向後搜索,找到第一個大於key的值,讓該值與key交換。

    (5)重複(3)、(4)不,直到i=j。

    列如:需要排序的數組A=[49,38,65,97,76,13,27]初始關鍵數據爲A[0]=49,經過第一趟快速排序後所有比49小的放在了49 的前邊,比49大的都放在了49的後邊。因此經過第一趟排序後的A=[27, 38, 13, 49, 76, 97, 65]記錄關機數據在經過第一輪快速排序後的位置i=3,因此A數組被分爲A1=[27, 38, 13]、A0=[49]、A2=[76, 97, 65]三個部分。

package cn.bsxy;
/**
 * 快速排序實現源碼
 * @author smartluobo
 *
 */

public class QuickSort {
    
    /**
     *
     * @a a需要進行排序的數組
     * @i i排序的其實位置關鍵數據的在數組中的位置,第一次調用i = 0
     * @j j需要進行排序終止位置。第一次調用是j=a.length-1
     * @return 返回經過一趟快速排序後關鍵數據的位置
     */

    public int partition(int[] a, int i, int j){//根據關鍵數據分割需要排序的數組並返回關鍵數據在分割後的位置
        int key = a[i];//臨時變量用於存儲關鍵數據
        while(i < j){
            while(i < j && a[j] >= key)//找出第一個比key小的數執行j--並將其賦值給a[i]
                j--;//執行j = j-1操作
                a[i] = a[j];//將a[j]的值賦值給a[i]
            

            while(i < j && a[i] <= key)//找出第一個比key大的數執行i++並將其賦值給a[j]
                i++;//執行i = i+1
                a[j] = a[i];//把該值賦值給a[j]
        }
        a[i]=key;//完成一趟快速排序後將選擇的關鍵數據放在分割點上
        return i;//返回關鍵數據在經過一趟快速排序後的位置
    }

    
    public void sort(int[] a, int i, int j){
        if(i < j){
            int n = partition(a ,i ,j);//記錄返回的關鍵數據在經過一趟快速排序後的位置
            sort(a,i,n-1);//對左邊部分進行遞歸調用。依次完成分割
            sort(a,n+1,j);//對右邊部分進行遞歸調用。依次完成分割
        }
    }
    
    public static void main(String[] args) {
        int[] a = {49,38,65,97,76,13,27};
        new QuickSort().sort(a, 0, a.length-1);
        for (int i : a) {
            System.out.print(i+"\t");
        }
    }
}

三、性能測試

    package cn.bsxy;

import java.util.Random;

/**
 *
 * @author smartluobo
 * 測試java交換排序的冒泡排序和快速排序兩種方法的性能
 */

public class SortTest {
    /**
     * 完成一趟快速排序
     * @param a 需要排序的數組
     * @param i 起始位置,第一次爲0
     * @param j 結束位置,一般爲數組的長度-1 a.length-1
     * @return
     */

    public int partition(int[] a,int i,int j){
        int key = a[i];
        while(i < j){
            while(i < j && a[j] <= key)
                j--;
            a[i] = a[j];
            while(i < j && a[i] >= key)
                i++;
            a[j] = a[i];
        }
        a[i] = key;
        return i;
    }
    
    /**
     * 快速排序方法實現。遞歸調用該方法完成數組的排序
     * @param a
     * @param i
     * @param j
     */

    public void sort(int[] a, int i, int j){
        if(i < j){
            int n = partition(a,i,j);
            sort(a,i,n-1);
            sort(a,n+1,j);
        }
    }
    
    /**
     * 冒泡排序方法實現
     * @param a 需要排序的數組
     */

    public static void maopaoSort(int[] a){
        int temp;
        for(int i = 0; i< a.length;i++){
            for(int j = 0;j<a.length-i-1;j++){
                if(a[j] < a[j+1]){
                    temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                }
            }
        }
    }
    
    /**
     * 創建一個長度很長的無序數組
     * @return
     */

    public static int[] createRandom(){
        int[] a = new int[18000];
        Random random = new Random();
        int b;
        for(int i = 0;i < a.length;i++){
            b = random.nextInt(100000);
            a[i] = b;
        }
        return a;
    }
    
    public static void main(String[] args) {
        int[] a = createRandom();        
        int[] b = a;//將a數組賦值給b是爲了保證兩個排序方法對完全一樣的兩個數組進行排序
        long maopaoStart = System.currentTimeMillis();
        maopaoSort(b);//使用冒泡排序法對生成的數組進行排序
        long maopaoEnd = System.currentTimeMillis();
        System.out.println("maopaoStart:"+maopaoStart+", maopaoEnd"+maopaoEnd+"快速排序法用                                時:"+(maopaoEnd-maopaoStart));
        long start = System.currentTimeMillis();
        new SortTest().sort(a, 0, a.length-1);//使用快速排序方法對生成的數組排序
        long end = System.currentTimeMillis();
        System.out.println("start:"+start+", end"+end+"快速排序法用時:"+(end-start));
//        int k = 0;
//        for (int i : a) {
//            k++;
//            System.out.print(i+"\t");
//            if(k%100 == 0){
//                System.out.println();
//            }
//        }

//   經打印測試冒泡排序和快速排序都能正常排序需要排序的數組

    }
}

運行以上代碼打印臺輸出爲:

maopaoStart:1456461874561, maopaoEnd1456461874976  快速排序法用時:415
start:1456461874977, end:1456461875059   快速排序法用時:82

經過多次測試後發現快速排序的速度比冒泡排序快 4~5倍。缺點是快速排序使用遞歸調用,當數組的長度足夠大時,會出現內存溢出的情況.....具體解決方案還望各位大神給出寶貴意見.





   



 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章