您的位置:首页 > 其它

最坏情况下的线性时间的选择算法

2014-11-18 17:16 387 查看
在上一篇文章中,我们提到了期望时间为线性的选择算法,而我们这次提到的最坏情况下的线性时间的选择算法。它的成功在于,它不是随机的选择关键数,它选择他们的中数作为关键数,这样提高了算法的速度。

算法的步骤:找出第i个最小的元素

1.将输入数组的n个元素划为【n/5】组,每一组5个元素,且至多只有最后一组由剩下的n mod 5个元素组成;

2.寻找每一组的中位数:对每一组元素进行插入排序,然后确定每组有序元素的中位数;

3.把每组找出的中位数重组为一个新的数组,找出其中位数x;

4.利用PARTITION,按找出的中位数对其进行划分,其中位数对应的下标为k;

5.如果i=k;则返回x,如果i<k,则递归的在低分区找第i个最小的元素,如果i>k,则递归的在高分区找第i-k个最小的元素。

#include <iostream>
#include <string.h>
using namespace std;

//对每个小组进行插入排序
void InsertionSort(int *a, int p, int r, int &mid)
{
int i;
for (int j = p + 1; j <= r; j++)
{
i = j - 1;
int key = a[j];
while (i >= p && a[i]>key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
int d = r - p + 1;
if (d % 2 == 0)
{
d = d / 2 - 1;
}
else
{
d = d / 2;
}
//cout<<d;
mid = a[d + p];
}

//寻找数组a的中位数,放到x中
void Select(int *a, int p, int r, int &x)
{
if (p == r)
{
x = a[p];
return;
}
int n = r - p + 1;
int m = 0;//组数
if (n % 5 == 0)
{
m = n / 5;
}
else
{
m = n / 5 + 1;
}

//将数组划分为五个一组五个一组...,每一组进行插入排序,并在排序后取出每一组的中位数,放入数组b中
int b[10] = {0};//记录每一组的中数
int i = p;
for (int j = 0; j<m; j++)
{
int mid;//每一行的中数
if (i + 4 <= r)//前面的几个整的行
{
InsertionSort(a, i, i + 4, mid);//用插入法对其排序
b[j] = mid;
i += 5;
}
else//最后可能不到5个数的行
{
InsertionSort(a, i, r, mid);
b[j] = mid;
}
//cout<<"i="<<i<<" mid="<<mid<<" j="<<j<<" m="<<m<<" r="<<r;system("pause");
}

//对包含各分组中位数的数组b,递归调用Select,找出中位数x
//Select(b, 0, m - 1, x);
InsertionSort(b, 0, m-1, x);
}

//根据中位数x,对数组a进行划分
int Partition(int *a, int p, int r, int x)
{
int index = -1;
for (int i = p; i <= r; i++)
{
if (a[i] == x)
{
index = i;//cout<<i;system("pause");
break;
}
}
if (index == -1)
{
cout << "error" << endl;
exit(1);
}
int temp = a[index];
a[index] = a[r];
a[r] = temp;

int i = p - 1;
for (int j = p; j<r; j++)
{
if (a[j] <= x)
{
i++;
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
int pivot = a[r];
a[r] = a[i + 1];
a[i + 1] = pivot;

return i + 1;
}

//寻找第i小的数
void find(int *a, int p, int r, int i, int &result)
{
int x;
Select(a, p, r, x);

//以x为主元,对数组a进行划分
int q = Partition(a, p, r, x);
int k = q - p + 1;
if (k == i)
{
result = a[q];
}
else if (k>i)
{
find(a, p, q - 1, i, result);
}
else
{
find(a, q + 1, r, i - k, result);
}
}

void Output(int *a, int n)
{
for (int i = 0; i<n; i++)
{
printf("%d ", a[i]);
}
cout << endl;
}

int main()
{
int n = 11;
int a[11];
for (int i = 0; i<n; i++)
{
a[i] = rand() % n;
}
Output(a, n);
int result = -1;
int i;
while (1)
{
cout << "输入你要查找的第i小:i=";
cin >> i;
find(a, 0, n - 1, i, result);
cout << "i=" << i << " result=" << result << endl;
}
//Output(a,n);
system("pause");
return 0;
}


代码我用的是这个师兄的博客点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: