利用快速排序解决选择问题:找出含有 N 个元素的表 S 中的第 k 个最小的元素...

查找集合 S 中第 k 个最小元的算法几乎与快速排序算法相同。事实上前三步是相同的,我们把这种算法叫做快速选择(quickselect)。另 | Si | 为 Si 中元素的个数:

    1) 如果 | S | = 1,则 k = 1, 并将S 中的元素作为答案返回。如果使用小数组的截止方法 | S | <= Cutoff, 则将 S 排序并返回第 k 个最小元。

    2) 选取一个枢纽元 v (v 属于 S)。

    3) 将集合 S 中的剩余元素 分割成 S1 和 S2,就像在快速排序中所做的那样。

    4) 如果 k <= | S1 |, 那么第 k 个最小元一定在 S1 中。在这种情况下,返回 quickselect(S1, k)。 如果 k = S1 + 1,那么枢纽元就是第 k 个最小元,将其返回即可。否则,第 k 个最小元在 S2 中, 它是 第(k - | S1 | - 1)个最小元,进行一次递归调用并返回 quickselect(S2 , k - | S1 | - 1)。

        与快速排序相比,快速选择只做了一次递归调用,而不是两次。快速选择的最坏情形和快速排序的相同,也是 O(N^2)。直观来看,只因为快速排序的最坏情形是发生在当 S1 或 S2 为空的时候【三数中值选取枢纽元可以使最坏情形发生的机会几乎是微不足道的】;于是,快速选择就不是真正的节省一次递归调用。不过,平均运行时间为 O(N)。

快速选择算法停止时,第 k 个最小元就在第 k 个位置上,这破坏了原来的顺序;如果不希望这样,那么需要做一份拷贝。

代码实现:

//利用快速排序解决选择问题:找出含有 N 个元素的表 S 中的第 k 个最小的元素
#include<iostream>
#define Cutoff 3
using namespace std;

typedef int ElemType;

void Swap_1(int *a, int *b)
{
 int tmp;
 tmp = *a;
 *a = *b;
 *b = tmp;
}
void InsertionSort(ElemType A[], int N)
{
 int i, j, tmp;
 for(i = 1; i < N; i++)
 {
  tmp = A[i];
  for(j = i; j > 0 && A[j - 1] > tmp; j--)
  {
   A[j] = A[j - 1];
  }
  A[j] = tmp;
 }
}

int Media_3(ElemType A[], int Left, int Right)
{
 int Center;
 Center = (Left + Right) / 2;
 if(A[Left] > A[Center])
  Swap_1(&A[Left], &A[Center]);
 if(A[Left] > A[Right])
  Swap_1(&A[Left], &A[Right]);
 if(A[Center] > A[Right])
  Swap_1(&A[Center], &A[Right]);
 Swap_1(&A[Center], &A[Right - 1]);
 return A[Right - 1];
}

void QuickSelect(ElemType A[], int k, int Left, int Right)
{
 ElemType Pivot;
 int i, j;
 if(Left + Cutoff <= Right)
 {
  Pivot = Media_3(A, Left, Right);
  i = Left;
  j = Right -1;
  for(;;)
  {
   while(A[++i] < Pivot){}
   while(A[--j] > Pivot){}
   if(i < j)
    Swap_1(&A[i], &A[j]);
   else
    break;
  }
  Swap_1(&A[i], &A[Right - 1]);

  if(k <= i)
   QuickSelect(A, k, Left, i - 1);
  else if(k > i + 1)
   QuickSelect(A, k, i + 1, Right);  
 }
 else
  InsertionSort(A + Left, Right - Left + 1);  //元素少于3个,可用直接插入排序
}

int main()
{
 int data[] = {3, 0, 4, 5, 8, 9, 7, 2, 6, 1};

 QuickSelect(data, 7, 0, 9);

 cout << data[7] << endl;

 for(int i = 0; i < 10; i++)
  cout << data[i] << " ";
 cout << endl;

 system("pause");
 return 0;
}

 

转载于:https://my.oschina.net/u/2260265/blog/340767

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值