linux快速排序,快速排序_Linux编程_Linux公社-Linux系统门户网站

思想

快速排序(quick sort)由C. A. R. Hoare在1962年提出。它的基本思想是:选择一个基准数(枢纽元),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都小于或等于基准数,另外一部分的所有数据都要大于或等于基准数,然后再按此方法对这两部分数据分别进行快速排序。

将数组 S 排序的基本算法由下列四步组成

如果 S 中元素个数是 0 或 1,则返回

取 S 中一元素 v,称之为枢纽元(pivot)

将S - {v}分成两个不相交集合:S1中的元素都小于或等于v,S2中的元素都大于或等于v

返回 { quickSort(S1) 后,继随 v,继而 quickSort(S2) }

枢纽元的选取

错误的做法

通常的、没有经过充分考虑的选择是将第一个元素或最后一个元素用作枢纽元。如果输入是随机的,那么这是可以接受的。但是如果输入是预排序的或是反序的,那么这样的枢纽元就产生一个劣质的分割,因为所有的元素不是都被划入了 S1 就是被划入了 S2。实际上,如果第一个元素用作枢纽元而且输入是预先排序的,那么快速排序花费的时间将是二次的。

pivot = A[right];

安全的做法

一种安全的做法是随机选取枢纽元。一般来说这种策略非常安全,因为随机的枢纽元不可能总在接连不断地产生劣质的分割。另一方面,随机数的生成一般代价昂贵,根本减少不了算法其余部分的平均运行时间。

pivot = Random(left, right);

exchange A[right] with pivot

三数中值分割法(Median-of-Three Partitioning)

一组 N 个数的中值是第 ⌈ N / 2⌉ 个最大的数。枢纽元的最好的选择是数组的中值。一般的做法是使用左端、右端和中心位置上的三个元素的中值作为枢纽元。下述函数将枢纽与置于最右边第二个位置。由于最左边的元素小于枢纽元、最右边的元素大于枢纽元,使得双向分割时i、j不会超出边界。

ElementType Median3(ElementType a[],intleft,intright){

int center = (left + right) / 2;

//sort a[left], a[center] and a[right]

if (a[left] > a[center])

Swap(&a[left], &a[center]);

if (a[left] > a[right])

Swap(&a[left], &a[right]);

if (a[center] > a[right])

Swap(&a[center], &a[right]);

Swap(&a[center], &a[right - 1]); //hide pivot

return a[right - 1]; //return pivot

}

分割策略

在分割阶段要做的就是把所有小元素移到数组的左边而把所有大元素移到数组的右边。调用该算法前应该使用好的策略选取枢纽元,并将其与最右边的元素交换(单向分割)或倒数第二个元素交换(双向分割),使其离开要被分割的区域: A[left] 到 A[right - 1] 或 A[left] 到 A[right - 2]。

单向分割

Partition(A, left, right)

pivot = A[right] //枢纽元位于最右边

i = left - 1

for j = left to right - 1

if(A[j] <= pivot)

i++

if(i != j )

exchange A[i] with A[j]

exchange A[i + 1] with A[right]

return i + 1

双向分割

pivot = Median3(a, left, right); //使用三数中值分割法获取枢纽元

i = left;j = right - 1;

for (; ; )

{

while (a[++i] < pivot) {}

while (a[--j] > pivot) {}

if (i < j)

Swap(&a[i], &a[j]);

else

break;

}

Swap(&a[i], &a[right - 1]); //restore pivot

算法主体

算法中的CUTOFF用于分辨排序的规模,因为当排序规模过小时宜采用直接插入排序。

#define CUTOFF 3

voidQuickSort(ElementType a[],intleft,intright){

int i, j;

ElementType pivot;

if (left + CUTOFF <= right)

{

pivot = Median3(a, left, right);

i = left; j = right - 1;

for (; ; )

{

while (a[++i] < pivot) {}

while (a[--j] > pivot) {}

if (i < j)

Swap(&a[i], &a[j]);

else

break;

}

Swap(&a[i], &a[right - 1]); //把枢纽元的位置恢复为两个集合的中间

QuickSort(a, left, i - 1);

QuickSort(a, i + 1, right);

}

else

InsertionSort(a + left, right - left + 1);

}

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值