平均時間複雜度爲O(nlogn)的排序算法

本文包括算法

1.快速排序數組

2.歸併排序數據結構

3.堆排序函數

 

1.快速排序ui

快速排序的基本思想是:採起分而治之的思想,把大的拆分爲小的,每一趟排序,把比選定值小的數字放在它的左邊,比它大的值放在右邊;重複以上步驟,直到每一個區間只有一個數。此時數組已經排序完成。spa

快速排序最重要的是partition函數功能的實現,也就是將比選定基數小的值放在他的左邊,比選定基數大的值放在它的右邊的功能函數。code

熟悉快速排序的人也許都會有本身的partition函數的寫法。此處,提供兩種不一樣的partition函數寫法。blog

例1:排序

public void partition(int[] a,int start,int end){
        if(start>=end)
            return ;
        int low=start;
        int high=end;
        int index = a[low];//選定基數
        while(low<high){
            while(a[high]>index && high>low)//找到右邊比基數小的數字
                high--;
            if(low<high)
                a[low++] = a[high];
            while(a[low]<index && high>low)//找到左邊比基數大的數字
                low++;
            if(low<high)
                a[high--] = a[low];
        }
        a[low] = index;
        partition(a,start,low-1);
        partition(a,low+1,end);    
    }

例2:遞歸

public void partition1(int[] a,int start,int end){
        if(start>=end)
            return ;
        int index = start;
        swap(a[index],a[end]);
        int small=start-1;
        for(index = start;index<end;index++){
            if(a[index]<a[end]){//若比選定基數小,則與前面比大於基數的數字進行交換
                small ++ ;
                if(small!=index){
                    swap(a[small],a[index]);
                }
            }
        }
        small++;
        swap(a[small],a[end]);
        partition1(a,start,small-1);
        partition1(a,small+1,end);
    }

快速排序

public void quickSort(int[] a){
        partition1(a,0,a.length-1);
}

快速排序的時間複雜度爲O(nlogn),最壞時間複雜度爲O(n^2),最壞的狀況適之每次區間劃分的結果都是基準關鍵字的最左邊或者右邊,即選擇的數字是待排序列中最小或者最大的。當n較大時使用較好。

 

2.歸併排序

歸併排序是利用遞歸與分治技術將數據序列劃分爲愈來愈小的半子表,再對半子表進行排序,最後在利用遞歸方法將排好序的半子表合併成爲愈來愈大的有序序列。

歸併排序中的歸,就是遞歸的意思,遞歸將數組分紅小的字數組。

例如數組[13,6,8,11]

先將數組分紅[13,6],[8,11]兩個數組,再將數組分爲[13],[6],[8],[11]。而後進行合併,[6,13],[8,11],最後合併爲[6,8,11,13]。

由於歸併排序須要將數組元素分割存儲,因此空間複雜度爲O(n),是以空間換時間的作法。

public void Merge(int[] a,int start,int mid,int end){
        int length1,length2; //新數組的大小
        int i,j,k;
        length1 = mid - start + 1;
        length2 = end - mid;
        int[] L = new int[length1];
        int[] R = new int[length2];
        for(i=0,k=start;i<length1;i++,k++)//將前半部分數組存入L中
            L[i] = a[k];
        for(i=0,k=mid+1;i<length2;i++,k++)//將後半部分數組存入R中
            R[i] = a[k];
        for(k=start,i=0,j=0;i<length1&&j<length2;k++){//分別從兩個數組中讀取數據,取較小的放入員數組中
            if(L[i]<R[j]){
                a[k] = L[i];
                i++;
            }
            else{
                a[k] = R[j];
                j++;
            }
        }
        if(i<length1)//將L中還有的剩餘數字存入原數組
            for(j=i;j<length1;j++,k++)
                a[k] = L[j];
        if(j<length2)//將R中還有的剩餘數字存入元素族
            for(i=j;i<length2;i++,k++)
                a[k] = R[i];
    }

調用歸併排序。

public void MergeSort(int[] a,int start,int end){
        if(start<end && a.length>1){
            int mid = (start+end)/2;
            MergeSort(a,start,mid);
            MergeSort(a,mid+1,end);
            Merge(a,start,mid,end);
        }
    }

歸併排序的時間複復雜度爲O(nlogn),且歸併排序是穩定的排序算法,適合n較大時使用。雖然歸併排序時間複雜度較低且具備穩定性,但由於其利用了O(n)的空間存儲數據,因此使用的時候須要綜合考慮。

 

3.堆排序

堆是一種特殊的樹形數據結構,每一個節點都有一個值,一般提到的堆是一棵徹底二叉樹,根節點的值小於或大於兩個節點的值,同時根節點的兩個子樹也分別是兩個堆。

堆排序的思想是對於給定的n個記錄,初始時把這些記錄看做成一棵順序的二叉樹,而後將其調整爲一個大頂堆,將堆的最後一個元素與堆頂的元素進行交換後,堆的最後一個元素即爲最大元素;接着將前(n-1)個元素從新調整爲一個大頂堆,再將堆頂元素與當前堆的最後一個元素進行交換後獲得次大的記錄,重複該過程知道調整的堆中只剩下一個元素爲止。此時已經獲得一個有序的數組。

簡要來講,堆排序就是兩個過程:構建堆;交換堆頂元素與最後一個元素的值。

public void adjustHeap(int[] a,int pos,int len){
        int temp;
        int child;
        for(temp = a[pos];2 * pos+1<=len;pos=child){
            child = 2 * pos+1;//獲得子節點的下標
            if(child<len&&a[child]<a[child+1])//獲得子節點中較大的節點
                child++;
            if(a[child] > temp)//將子節點和父節點進行交換
                a[pos] = a[child];
            else
                break;
        }
        a[pos] = temp;
    }
    //堆排序
    public void HeapSort(int[] a){
        for(int i=a.length/2-1;i>=0;i--)//構建堆
            adjustHeap(a,i,a.length-1);
        for(int i=a.length-1;i>=0;i--){
            //把第一個數字和最後一個數字交換
            int temp = a[0];
            a[0] = a[i];
            a[i] = temp;
            //調整堆保證第一個數字是最大的
            adjustHeap(a,0,i-1);//調整剩下i-1個元素
        }
    }

堆排序的時間複雜度也爲O(nlogn),一樣適合n較大時使用。

相關文章
相關標籤/搜索