数组的前k个最大值

方法一:使用最小堆。

 1、用前k个元素建立一个最小堆;

2、遍历无序区域的元素,和堆顶元素对比,如果小于堆顶值,肯定不可能是前k个最大值;如果大于堆顶值,那么取代堆顶元素,做一次堆调整。

//最小堆的调整
void heap_adjust_for_maxK(int arr[], int s, int end)
{
	//对堆进行一次调整
	//方法:(以大顶堆为例)比较父节点和两个子节点的大小:如果父节点大,无需调整;
	//													 如果子节点大,那么和父节点交换;
	//														继续调整该节点
	//退出条件:left节点超出end;或者父节点比子节点大
	int next = s;
	int father = 0;
	int left = 0;
	int right = 0;

	while( (left=father*2 + 1) <= end )
	{
		right = left + 1;
		next = left;
		if(right<=end && arr[right]<arr[left])
		{
			next = right;
		}

		if(arr[next] < arr[father])
		{
			int temp = arr[father];
			arr[father] = arr[next];
			arr[next] = temp;
		}
		else
		{
			break;
		}

		father = next;
	}



	return;
}

void maxK(int arr[], int num, int k)
{
	if(k >= num)
	{
		return;
	}

	//创建前k个数的最小堆
	for(int i=k/2-1; i>=0; i--)
	{
		heap_adjust_for_maxK(arr, i, k-1);
	}

	//从后面的非最小堆区域,遍历每个元素,与最小堆的对顶比较,如果小于堆顶元素,继续下一个;否则,取代堆顶元素,并做一次调整
	for(int j=k; j<num; j++)
	{
		if(arr[j] > arr[0])
		{
			arr[0] = arr[j];
			heap_adjust_for_maxK(arr, 0, k-1);
		}
	}

}


方法二:改进快速排序
int partion(int arr[], int left, int right)
{

    int base = arr[left];
    int i = left;
    int j = right;

    while(i < j)
    {
        while(j>i && arr[j]<=base)
            j--;
        while(j>i && arr[i]>=base)
            i++;

        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }


    arr[left] = arr[i];
    arr[i] = base;

    return i;
}

//思路:先对数组进行一次切分,此时基准点在mid位置,其左边都是大于基准的数据,
//        如果此时基准点在前k各数里面,则继续对mid之后的数组进行切分;
//        如果此时基准点在前k各数外面,则继续对mid左侧的数组进行切分
//终止条件:mid在k各数的最右边。
//这个条件一定会终止,这就是mid-1, mid+1的原因
void quick_sort(int arr[], int left, int right, int k)
{
    int mid = 0;
    if(left<right)
    {
        mid = partion(arr, left, right);

        while(mid != k-1)
        {
            if(mid > k-1)
            {
                mid = partion(arr, left, mid-1);
            }
            else
            {
                mid = partion(arr, mid+1, right);
            }
        }
    }
}

方法三:额外用一个k个节点的树存放

前两种方法都会对数组造成破坏,用这种方法则不会。

c++中可以使用multiset

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值