經典排序算法的詳細分析及C++實現代碼

1、冒泡排序  O(n2)
每一次把最大的移動到最右端,第一次從0~n-1中找到最大的放到n-1處,第二次從0~n-2中找到最大的放到n-2處……
classBubbleSort {
public:
    int* bubbleSort(int* A, intn) {
        inti,j,temp = 0;
        for(i = 1;i < n;i++)
            for(j = 0; j < n - i;j++) {
            if(A[j] > A[j + 1]) {
                temp = A[j + 1];
                A[j + 1] = A[j];
                A[j] = temp;
            }
        }
        returnA;
    }
};
2、選擇排序  O(n2)
先把0處的看作最小值,從1~n-1中找到比它小的值,交換;再把1處的看作最小值,從2~n-1中找到比他小的,交換;……
classSelectionSort {
public:
    int* selectionSort(int* A, intn) {
        if(n == 0) returnA;
        inti,j,min = 0,temp;
        for(i = 0;i < n;i++) {
            min = i;
            for(j = i+1;j < n;j++) {
                if(A[j] < A[min]) {
                    min = j;
                }
            }
           temp = A[i];
           A[i] = A[min];
           A[min] = temp;                    
        }      
        returnA;
    }
};

3、插入排序  O(n2)
先把0處看作已排序的序列,將1~n-1處逐個地與0處比較,若比0處小,則將其插入到已排序的序列中;……;假設0~3已排序,將4~n-1處依次與3處比較,若小於3處,則將其插入到0~3的適當位置;……
classInsertionSort {
public:
    int* insertionSort(int* A, intn) {
        inti,j,k,temp;
        for(i = 1;i < n;i++) {
            k = i;
            for(j = i-1;j >=0;j--) {
            if(A[k] < A[j]) {
                temp = A[k];
                A[k] = A[j];
                A[j] = temp;
                k = j;
            }               
            }                     
        }
         returnA;  
    }
};

4、歸併排序(遞歸)  O(NlogN) 
先將序列分成2個子序列,再分成4個,……,直到所有子序列都只含一個元素;對每個子序列排序,再將相鄰的兩個已排序子序列歸併爲一個排序序列,依次類推,最後歸併出原序列的排序序列。
classMergeSort {
public:
 
    voidMerge(int* A,intstart,intmiddle,intend) {
        inttemp[end-start +1];
        intk = 0;
        for(inti = start,j = middle + 1;i <= middle || j <= end;k++) {
            if(i <= middle && j <= end) {
                if(A[i] < A[j]) {
                temp[k] = A[i];
                i++;
            }
            else{
                temp[k] = A[j];
                j++;
            }
            }
            elseif(i <= middle) {
                temp[k] = A[i];
                i++;
            }
            else{
                temp[k] = A[j];
                j++;
            }
                      
        }
        for(intm = 0;m < k;m++)
            A[start + m] = temp[m];
    }
    voidDivide(int* A,intstart,intend) {

        if(start < end) {
            intm = (start + end)/2;
            Divide(A,start,m);
            Divide(A,m+1,end);
            Merge(A,start,m,end);
        }
       
    }
    int* mergeSort(int* A, intn) {
        Divide(A,0,n-1);
        returnA;
    }
};

5、快速排序(遞歸)  O(NlogN)
先從序列中選取一個元素爲基數,一般選最左邊一個;兩個指針i、j分別從序列的頭尾向中間遍歷;j從右到左找到小於基數的元素(j處),複製到基數處(i處),i++;然後i從左向右找到大於基數的元素(i處),複製到j處,j--;依次類推,直到i與j相遇使i>=j,while循環結束,此時已把序列分成左右兩個子序列,左邊小於基數,右邊大於基數;再將左右子序列當做未排序序列進行遞歸。
class QuickSort {
public:
    void Quick(int* A,int start,int end) {
        if (start >= end) return;
        else {
            int i = start,j = end;
            int base = A[i];
            while (i < j) {
                while (i < j && A[j] > base) j--;
                if (i < j) {
                    A[i] = A[j];
                    i++;
                }
                while (i < j && A[i] < base) i++;
                if (i < j) {
                    A[j] = A[i];
                    j--;
                }
            }
            A[i] = base;
            Quick(A,start,i - 1);
            Quick(A,i + 1,end);
        }
    }
    int* quickSort(int* A, int n) {
        // write code here
        Quick(A,0,n-1);
        return A;
    }
};

6、堆排序 O(NlogN)
堆實際上是一種思想,不是一種數據存儲結構,堆中數據的邏輯結構與完全二叉樹一樣,設總共有n個結點,則葉結點個數爲n+1/2或者n/2,則非葉子結點個數爲n-1/2或者n/2,當n能被2整除時爲n/2,不能被整除時爲n-1/2。
思路:
(1)堆化數組。給定一個長度爲n的亂序數組,若要遞增排序,則先將其堆化(按層序存儲),即把原數組調整爲大端堆。
(2)取堆頂元素放入數組末尾。每次將堆頂元素與數組末尾元素交換。
(3)調整交換元素後的堆。再從堆頂到第n-2個元素調整數組爲大端堆,直到n-2=1爲止,即堆中只剩下一個元素未放入排序序列爲止。
classHeapSort {
public:
     
    void heapify(int* A,inti,intn) {
        intj,temp;
        temp = A[i];
        j = 2*i + 1;
         
        while(j < n) {
            if(j + 1< n && A[j+1] > A[j]) j++;
            if(A[j] <= temp) break;
                A[i] = A[j];
                i = j;
                j = 2*i +1;
 
        }
        A[i] = temp;
        return;
    }
     
    int* heapSort(int* A, intn) {
        // write code here
        int temp;
        for(int m = n/2- 1;m >= 0;m--)
            heapify(A,m,n);
        for(int k = n-1;k >= 1;k--) {
            temp = A[k];
            A[k] = A[0];
            A[0] = temp;
            heapify(A,0,k);
        }
        return A;
    }
};


7、希爾排序 O(NlogN)
插入排序的改進。每一次比較的步長是變化的。例如,長度爲n的數組,第一次設置步長爲n/2,認爲前n/2個數已經排序,從第n/2+1個開始,將其逐個與第1個、2個……比較,大於則交換,小於則不做操作。然後減小步長,繼續以上步驟直到步長變爲1.
classShellSort {
public:
    int* shellSort(int* A, intn) {
        // write code here
        intspan = n/2;
        inti,j,temp;
         
        while(span >= 1) {
            for(i = span;i < n;i++) {
                j = i - span;
                while(j >= 0) {
                    if(A[j] > A[i]) {
                        temp = A[j];
                        A[j] = A[i];
                        A[i] = temp;                         
                    }
                    j -= span;
                }
            }
            span--;
        }
        returnA;
    }
};

8、計數排序 O(N)
(1)先確認待排序數組A元素的取值範圍,相當於找出最大值max和最小值min,桶C的大小必須要能包含所有的元素。
(2)順序遍歷數組A,把A[i]與桶C的下標對應起來,即,將C[A[i]-min]加1。這樣A最小的元素與C的第一個下標對應,最大元素與C的最後一個下標對應。這個過程相當於把A中元素裝入對應的桶中。
(3)順序遍歷桶C,把桶中元素按順序倒出來,就是從小到大的已排序序列。
classCountingSort {
public:
    int* countingSort(int* A, intn) {
        // write code here
        intmax = A[0],min = A[0];
        for(inti = 0;i < n;i++) {
            if(A[i] > max) max = A[i];
            if(A[i] < min) min = A[i];
        }         
        intsizeC = max - min + 1;
        int*C = newint[sizeC]; 
        for(inti = 0;i < sizeC;i++)
            C[i] = 0;         
        for(intj = 0;j < n;j++) {
            C[A[j]-min]++;
        }
        intz = 0;
        for(intm = 0;m < sizeC;m++) {
            while(C[m] > 0) {
                A[z] = m + min;
                z++;
                C[m]--;
            }            
        }
        delete []C;
        returnA;
    }
};

9、基數排序 O(N)
先根據個位把各元素入桶,把桶中元素倒出來得到按個位排序的序列;再按照十位把各元素入桶,倒出來得到按十位排序的序列;以此類推……
注:A中數據小於2000.
一維數組實現:
classRadixSort {
public:
    int* radixSort(int* A, intn) {
        // write code here
        intC[10];
        intdivisor[5] = {1,10,100,1000,10000};
        int*B = newint[n];
        for(inti = 0;i < 4;i++) {
            for(intj = 0;j < 10;j++)
                C[j] = 0;
            for(intk = 0;k < n;k++) {
                intunit = (A[k]%divisor[i+1])/divisor[i];
                C[unit]++;
            }
            for(intj = 1;j < 10;j++)
                C[j] += C[j-1];
             
            for(intk = n-1;k >= 0;k--) {
                intunit = (A[k]%divisor[i+1])/divisor[i];
                B[C[unit]-1] = A[k];
                C[unit]--;
            }
            for(intj = 0;j < n;j++)
            A[j] = B[j];          
        }
        delete []B;
        B = NULL;
        returnA;
    }
};

二維數組實現:
class RadixSort {
public:    
int* radixSort(int* A, int n) {
        // write code here
        vector<deque<int> > bucket(10);
        int divisor[] = {1,10,100,1000,10000};
        for (int i = 0;i < 4;i++) {
            for (int j = 0;j < n;j++) {
                int unit = (A[j]%divisor[i+1])/divisor[i];
                bucket[unit].push_back(A[j]);
            }
            for (int j = 0, k = 0;j < 10;j++) {
                while (!bucket[j].empty()) {
                    A[k++] = bucket[j].front();
                    bucket[j].pop_front();
                }
            }
        }
        return A;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章