Python實現快速排序--數據結構


快速排序(Quick Sort)

快速排序是由東尼·霍爾所發展的一種排序算法。在平均狀況下,排序n個元素要O(nlogn)次比較。在最壞狀況下則需要O(n^2)次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他O(nlogn)算法更快,因為它的內部循環可以在大部分的架構上很有效率地被實現出來。

  快速排序使用分治策略(Divide and Conquer)來把一個序列分為兩個子序列。步驟為:

  1. 從序列中挑出一個元素,作為"基准"(pivot).一般使用第一個元素或最后一個元素作為比較的基准。
  2. 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的數可以到任一邊),這個稱為分區(partition)操作。
  3. 對每個分區遞歸地進行步驟1~2.

Python代碼:

def Partition(seq,left,right):
    key=seq[right]
    tail=left-1
    for i in range(left,right):
        if seq[i]<=key:
            tail+=1
            if tail!=i:
                seq[tail],seq[i]=seq[i],seq[tail]
    seq[tail+1],seq[right]=seq[right],seq[tail+1]
    return tail+1
def QuickSort(seq,left,right):
    if left>=right:
        return
    index=Partition(seq,left,right)
    QuickSort(seq,left,index-1)
    QuickSort(seq,index+1,right)
    return seq
    
s = [6, 8, 1, 4, 3, 9, 5, 4, 11, 2, 2, 15, 6]
print("before sort:",s)
s1 = QuickSort(s, left = 0, right = len(s) - 1)
print("after sort:",s1)            

 

本文將要實現快排的一種思路如下:

第一個函數Partition()的作用是:給定一個序列和序列的起始位置和末尾元素的位置,以末尾元素為基准,將小於基准的數據放在基准的左邊,大於基准的數據放在右邊,最后返回基准數據的索引下標

第二個函數QuickSort()的作用是不斷的遞歸循環,直到出現left>=right的情況結束

其中,最難理解的是Partition函數。在這里做如下解釋:

 例如一組數據:s = [6, 8, 1, 4, 3, 9, 5, 4, 11, 2, 2, 15, 7],n=siezof(s)

第一步:以序列的最后一個元素作為基准,pivot=7

第二步:從左到右遍歷前n-1個元素,這里先借助一個輔助變量tail,tail的作用是作為一個索引,用來表示遍歷過程中,所有比基准小的數組成的子序列中的最后一個元素的索引。特別繞!例如遍歷s,一個元素6要比pivot=7小,所以子序列為[6],tail值為0,然后繼續向前遍歷,第二個元素8比pivot大,跳過,遍歷第三個元素1要比pivot小,那么子序列為[6,1],tail值為2,遍歷第四個元素4要比pivot小,那么子序列為[6,1,4],tail值為3,.。。。最后tail+1即為pivot=7在原序列中的位置。

C代碼:摘自:http://www.cnblogs.com/eniac12/p/5329396.html

#include <stdio.h>

void Swap(int A[], int i, int j)
{
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

int Partition(int A[], int left, int right)  // 划分函數
{
    int pivot = A[right];               // 這里每次都選擇最后一個元素作為基准
    int tail = left - 1;                // tail為小於基准的子數組最后一個元素的索引
    for (int i = left; i < right; i++)  // 遍歷基准以外的其他元素
    {
        if (A[i] <= pivot)              // 把小於等於基准的元素放到前一個子數組末尾
        {
            Swap(A, ++tail, i);
        }
    }
    Swap(A, tail + 1, right);           // 最后把基准放到前一個子數組的后邊,剩下的子數組既是大於基准的子數組
                                        // 該操作很有可能把后面元素的穩定性打亂,所以快速排序是不穩定的排序算法
    return tail + 1;                    // 返回基准的索引
}

void QuickSort(int A[], int left, int right)
{
    if (left >= right)
        return;
    int pivot_index = Partition(A, left, right); // 基准的索引
    QuickSort(A, left, pivot_index - 1);
    QuickSort(A, pivot_index + 1, right);
}

int main()
{
    int A[] = { 5, 2, 9, 4, 7, 6, 1, 3, 8 }; // 從小到大快速排序
    int n = sizeof(A) / sizeof(int);
    QuickSort(A, 0, n - 1);
    printf("快速排序結果:");
    for (int i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM