多个有序数列中查找第k小值

        问题描述:现有n个有序序列如(2,3,9),(3,5,11,23),(1,4,7,9,15,17,20),(8,15,35,9),(20,30,40),请求出第k小值。


     问题分析:可用多路归并排序将所有序列进行排序后取第k个值,但是只要求求出第k小值将所有数组排序未免显得有点浪费,所以我们可以使用包含k个元素的堆完成,对于每组元素取出前k小的,依次进行比较,得到总的前k小


     执行步骤:

一、建初堆:从第一组数中取出前k小的元素建初始大根堆(若不足k个则取全部元素),

二、

1 、补充堆:若堆中元素不足k个,则从下一组数中获取来补足

2、与该组元素比较:否则从下一组的第一个元素开始,依次与堆顶元素比较,

       (1)若小于堆顶元素,则将该元素与堆顶元素交换,调整堆,从该组的下一个元素开始重复第2部的操作一直到该组的第k个数

      (2)剪枝:若大于堆顶元素,说明后面的均会大于堆顶元素,则结束该组的比较操作

三、循环进行二的操作,直到所有数组比较完毕

四、堆顶元素即为第k小的元素


    举例说明:以题目序列为例,k为5

一、建初堆,因为数组一只有三个元素,所有初始堆为三个元素


1、补充堆,因为堆中元素不足5个,所有用第二组元素将堆补充完整,得:


2、第二组第三个元素为11,大于堆顶元素9,属于第(2)种情况,要剪枝,所以第二组后面元素不再与堆顶元素比较

三、从第三组数到第n组数,依次执行第二步的操作

四、最终得出的堆为


所以第五大元素为堆顶元素4


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
d”。 二分法是一种高效的查找算法,可以在有序数列快速定位指定值。具体实现步骤如下: 1. 定义左右指针left和right,分别指向数列的起始和结束位置。 2. 计算间位置mid,即mid=(left+right)/2。 3. 比较间位置的值与指定值y的大小关系: a. 如果mid位置的值等于y,则找到了目标值,输出查找次数(即循环次数),并输出其在数组中对应的下标。 b. 如果mid位置的值大于y,则说明目标值在左半部分,将right指针移动到mid-1位置。 c. 如果mid位置的值小于y,则说明目标值在右半部分,将left指针移动到mid+1位置。 4. 重复步骤2-3,直到left>right为止。 如果数列存在多个y,可以在找到第一个y后,继续向左和向右查找,直到找到所有的y为止。输出时按下标序号顺序输出。 如果数列不存在y,则输出“not found”。 代码实现如下: ``` #include <iostream> using namespace std; int main() { int n, y; cin >> n >> y; int a[n]; for (int i = ; i < n; i++) { cin >> a[i]; } int left = , right = n - 1, cnt = ; bool found = false; while (left <= right) { int mid = (left + right) / 2; cnt++; if (a[mid] == y) { found = true; cout << cnt << endl; int i = mid; while (i >= && a[i] == y) { cout << i << " "; i--; } i = mid + 1; while (i < n && a[i] == y) { cout << i << " "; i++; } cout << endl; break; } else if (a[mid] > y) { right = mid - 1; } else { left = mid + 1; } } if (!found) { cout << "not found" << endl; } return ; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值