快速排序的基本理念
快速排序本质上还是分治法来进行排序,所以还是参考这个前面提到的分析方法。
所以快速排序可以分为三个部分:

具体实现
选一个数,把比他小的放前面,比他大的放后边,然后通过递归不断缩小范围,直到全部排序好。
方法
主要分为两个板块:
- 递归分治
- 数组分割
其中递归分治中就用到了数组分割
递归分治
很好理解,就是把数组拆分为三个部分:
- 主元x,这个是标杆,围绕他来划分数组
- 比主元小的部分
- 比主元大的部分
数组分割
首先选择一个主元x,主元可以任意选择,这里以选择最后一个元素为例。
同时设立两个指针变量i,j:
其中j指向最左元素,i指向最左元素的左边一个元素(其实没什么必要,可以改为i,j都指向最左元素)
下面展示的是在分割过程中数组的状态

然后将j向后遍历,如果遇到比x大的元素则收纳,到比x小的就将其通过交换调到前面去。
在交换之前i指针向后移指向比主元大部分的第一个元素,保证在交换后i是指向的比x小的最后一个元素

在最后,将主元与(>x)部分的第一个元素交换,以确保顺序不乱
在算法导论中提到的方法是lomuto划分,还有一种常见的是霍尔提出的划分方法
lomuto划分的两个指针都是从左边开始,霍尔划分是从两边开始,在下面的伪代码部分我会提供霍尔划分的伪代码
伪代码
- 递归排序

- 数组划分
lomuto:

霍尔:

C语言代码
#include<stdio.h>
//自己写的数组交换函数
void swap(int A[], int i, int j)
{
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
int HoarePartition(int A[],int p,int r)
{
int i=p;
int j=r;
int x=A[i];
while(i<j)
{
//j从右边开始找比x小的元素
while(i<j && A[j]>=x)
j--;
if(i<j)
A[i]=A[j];
//i从左边开始找比主x的元素
while(i<j && A[i]<=x)
i++;
if(i<j)
A[j]=A[i];
}
A[i]=x;
return i;
}
//进行分割排序,同时返回主元
int partition(int A[],int p,int r)
{
int x = A[r];
int i = p-1;
int j;
//j从第一位开始往后遍历,遇到比x大的就收纳,遇到比x小的就将其与调到前面去(通过交换)
for(j = p; j <= r-1; j++)
{
if(A[j]<=x)
{
i = i+1;
swap(A, i, j);
}
}
//最后一步将主元x放到正确的位置
swap(A, i+1, r);
return i + 1;
}
int quicksort(int A[], int p, int r)
{
if(p<r)
{
//q是主元,那么q左边的就是小于A[q]的,右边就是大于A[q]的
int q = partition(A, p, r);
//递归排序,递归出口就是上面的if条件
quicksort(A, p, q-1);
quicksort(A, q+1, r);
}
}
int main()
{
int A[] = {2, 5, 3, 1, 10, 4};
int n = 6;
quicksort(A, 0, n-1);
for(int i; i<n; i++)
{
printf("%d ",A[i]);
}
return 0;
}
本文深入解析了快速排序算法,包括其基本理念、具体实现步骤、递归分治策略、数组分割技巧及C语言代码示例。介绍了主元选择、指针遍历等关键操作,并对比了lomuto和霍尔两种不同的划分方法。
2209

被折叠的 条评论
为什么被折叠?



