内排序算法总结——快速排序

来源:互联网 发布:软件测试工程师面试题 编辑:程序博客网 时间:2024/05/16 17:39

快速排序

快速排序是一种在含n个数的输入数组上最坏情况运行时间为O(n2)的算法,平均性能的期望运行时间为O(nlgn),且O(nlgn)记号中隐含的常数因子很小。另外,它还能够进行原地置换排序。

快速排序是基于分治模式上的,分治过程三个步骤

1.分解:把数组A[p...r]分成两个非空子数组A[p...q]和A[q+1...r],使得A[p...q]的每个元素都小于等于A[q+1...r]中的元素,下标q也在这个划分过程中进行计算。

2.解决:通过递归调用快速排序对子数组A[p...q]和A[q+1...r]排序。

3.合并:因为两个子数组是原地排序的,不需要将它们合并,整个数组A[p...r]已排序。

过程如下:

QuickSort(A,p,r)

{

     if p<r

     then q = Partition(A,p,r);

    QuickSort(A,p,q);

    QuickSort(A,q+1,r);

}

快速排序算法的关键是Partition过程,它对子数组A[p...r]进行划分,并得到划分的界限q:

Partition(A,p,r)

{

    x = A[p];

    i = p-1;

    j = r+1;

   while TRUE

       do repeat j = j-1

              until A[j] <= x

           repeat i = i+1

              until A[i] >= x

           if  i<j

              then swap (A[i] , A [j])

            else return j

}

代码如下:

void Swap(int &a, int &b)
{
    
int t = a;
    a 
= b;
    b 
= t;
}

int Partition(int *A, int left, int right)
{
    
int x = A[left];
    
int i = left - 1;
    
int j = right;

    
while(1)
    
{
        
while(A[j]>x)
            
--j;
        
while(A[i]<x)
            
++i;
        
if(i<j)
            Swap(A[i],A[j]);
        
else return j;
    }

}

void QuickSort(int* A,int left, int right)
{
    
if(left < right)
    
{
        
int q = Partition(A,left,right);
        QuickSort(A,left,q);
        QuickSort(A,q
+1,right);
    }

}

void PrintArray(int data[], int n)
{
    
int i;
    
for(i = 0; i < n; i++)
    
{
        printf(
"%d ", data[i]);
    }

    printf(
" ");
}

void main()
{    
    
int A[] = {4144-12512530};
    QuickSort(A,
0,6);
    PrintArray(A,
7);
}

当数组已经排序好(正序)时,快速排序的的时间代价是O(n2),而这对插入排序只要O(n)的时间

因为此时把数组划分为两部分,分别含1个和n-1个的数组,而快速排序的最佳情况是两个子数组大小都是n/2

改进(随机化版本):当数组还没有被划分时,可将元素A[p]与A[p...r]中随机选出的一个元素交换。

只要把Partition函数开头加入随机化即可:

Randomized_Partition(A,p,r)

{

     i = Random(p,r)

     swap (A[p],A[i])

     return Partition(A,p,r)

}

相应地,在QuickSort里调用Randomized_Partition(A,p,r)

代码如下:

 

void Swap(int &a, int &b)
{
    
int t = a;
    a 
= b;
    b 
= t;
}


int Partition(int *A, int left, int right)
{
    
int x = A[left];
    
int i = left - 1;
    
int j = right;

    
while(1)
    
{
        
while(A[j]>x)
            
--j;
        
while(A[i]<x)
            
++i;
        
if(i<j)
            Swap(A[i],A[j]);
        
else return j;
    }

}


int new_random(int min, int max)
{
    
return (min + (int)(((float)rand()/RAND_MAX)*(max - min)));
}

int Randomized_Partition(int *A, int left, int right)
{
    
int i = new_random(left, right);
    Swap(A[i], A[right]);
    
return Partition(A, left, right);
}

void Randomized_QuickSort(int* A,int left, int right)
{
    
if(left < right)
    
{
        
int q = Randomized_Partition(A,left,right);
        QuickSort(A,left,q);
        QuickSort(A,q
+1,right);
    }

}

void PrintArray(int data[], int n)
{
    
int i;
    
for(i = 0; i < n; i++)
    
{
        printf(
"%d ", data[i]);
    }

    printf(
" ");
}

void main()
{    
    
int A[] = {4144-12512530};
    Randomized_QuickSort(A,
0,6);
    PrintArray(A,
7);
}

 

另外,还有一个方案,是在待排序的数组里随机选三个元素,取值为第二大的那个作为基准数也可