9.3-6 k分位数

题目描述:对一个包含n个元素的集合来说,k分位数是指能把有序集合分成k个等大小集合的第k-1个顺序统计量。给出能找出某一集合的k分位数的O(nlgk)时间的算法。

k分位数解释:

点击打开链接

令每个子集合的元素个数为t = n / k,A[j]是数组A中下标为j的元素,A(j)是数组是第j大的元素

则所求的k分位数是指A(t),A(2t),A(3t),……,A((k-1)t)


直接搜索k次达不到时间要求,可采用如下思路求解:

 1、先找A(t),A(2t),A(3t),……,A((k-1)t)中间的第kt/2个顺序统计量;

 2、第一步查找结束后,数组分成前后两半,接着依次处理这两个子数组。

代码如下:(只考虑了n是k的整数倍的情况)

#include <iostream>
using namespace std;
void exchange(int &a, int &b)
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}
int partition(int A[],int p, int r, int key)
{
	int i = p - 1,j;
	for(j=p;j<r; ++j)
		if(A[j]==key)
			break;
	exchange(A[j],A[r]);
	for(j=p; j<r; ++j)
	{
		if(A[j]<=key){
			i++;
			exchange(A[i],A[j]);
		}
	}
	exchange(A[i+1],A[r]);
	return i+1-(p-1);
}
void insert_sort(int A[],int p, int r)
{
	if(p>=r)
		return;
	int key,i,j;
	for(j=p+1;j<=r; j++)
	{
		key = A[j];i=j-1;
		while(i>=p && A[i]>key)
		{
			A[i+1] = A[i];
			i = i-1;
		}
		A[i+1] = key;
	}
}
int select(int A[],int p, int r, int i)
{
	if(p==r)
		return A[p];
	int k = p+4;
	while(k<=r)
	{
		insert_sort(A, k-4, k);
		k += 5;
	}
	insert_sort(A, k-4, r);
	int num;
	num = (r-p+1)/5 + ( (r-p+1)%5 ? 1:0 );
	int *new_arr = new int[num];
	for(int j=0;j<num-1;++j)
		new_arr[j] = A[3+j*5+p-1];
	//找出最后一个中位数
		k = r-(num-1)*5 - (p - 1);
	if(k%2)k = k + 1;
	k = k/2;
	k += (num-1)*5 + p - 1;
	new_arr[num-1] = A[k];
	//对[n/5]个中位数进行插入排序,找出中位数的中位数x
	insert_sort(new_arr, 0, num-1);
	int x = new_arr[(num-1)/2];
	delete new_arr;
	//按中位数x对输入数组进行划分
	k = partition(A,p,r,x);
	if(k==i)
		return x;
	else if(k>i)
		select( A, p, k-1 + (p-1), i);
	else
		select( A, k+1 + (p-1), r, i-k);
}
void find_k(int A[],int p, int r, int k)
{
	if(k<1)return;
	int len = (r-p+1)/k;
	int i;
	i = k/2;
	if(i>0){
		select(A,p,r,i*len);
		find_k(A,p,i*len+(p-1),k/2);
		find_k(A,i*len+p,r,k%2?k/2+1:k/2);
	}
}
void test()
{
	int A[] = {0,5,15,14,13,12,9,10,7,3,2,4,6,8,1,11,17,16,18,20,19};
	find_k(A,1,20,5);
	for(int i=1;i<5; ++i)
		cout<<A[i*4]<<" ";
	cout<<endl;
}
int main()
{
	test();
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值