找第k小的数

找第k小的数

问题描述

给定一个数组A = A[1,...,n]和一个下标i(1 <= i <= n),找出数组A内第i小的数。

例如i=1则是找到最小的数,i=n则是找到最大的数。

解决办法

1. 将数组升序排序,然后遍历取出第i个数即为所求。
2. 如果数组的取值范围波动不大,则可以通过用空间换取时间的方式来求解。即
Algorithm : findKTh(A,k)
    1. 申请一个大小为max(A) + 1的数组B,依次遍历数组A,将A中的值作为B中的下标,值为1。
   如A[1,3],则B = new int[4]. b[0]=0,b[1]=1,b[2]=0,b[3]=12. 遍历数组B,第k个值为1的数即为所求。
3. 利用中位数的中位数求解(复杂度为O(n))。由于我们只需要求第i小的数(仅一个数),没必将数组完全排序。
   Algorithm : findKTh(A,k)
      1. 将输入数组的n个数分割为Math.ceil(n/5)数组,每个数组个数是5。(可能有一个数组的个数是n%5)
      2. 步骤1所得的数组个数为
         1. 1个,则求该数组的中位数即为中位数的中位数。
         2. 大于1个,则分别求出每个数组的中位数。然后将将所有的中位数作为入参执行步骤13. 以步骤2的结果为pivot,进行Partition.(算法导论7.1章)
      4. 设步骤3Partition所得结果中,pivot的位置为i
         if k = i then return x.
         else,if k < i, 递归调用findKth(A[1,...,i-1],i)
         else,if k > i, 递归调用findKth(A[i+1,...],k-i)

算法备注

三个数中取中位数(最多三次比较)
algorithm : findMedian(a,b,c)
      1. if a > b , then swapValue(a,b)
      2. if c < a , return  a
         if c > b , return b
         else , return c 
四个数取中位数(四次比较,默认第二小为中位数)
algorithm : findMedian(A[a,b,c,d])
      1. if a > b , then swapValue(a,b) //保证 a<b
      2. if c > d , then swapValue(c,d) //保证 c<d 
      3. if a > c , then swapValue(b,d),swapValue(a,c) //c是最小值,不是中位数。保证a<b c<d a<c
      4. if b < c , return b
         else return c
五个数中取中位数()
algorithm : findMedian(A[a,b,c,d,e])
      1. if a > b , then swapValue(a,b) //保证 a<b
      2. if c > d , then swapValue(c,d) //保证 c<d 
      3. if a > c , then swapValue(b,d),swapValue(a,c) //c是最小值,不是中位数。保证a<b c<d a<c
      4. if b > e , then swapValue(b,e) 
      5. if b > c , then swapValue(b,c)
      6. if c > e , then swapValue(c,e)
         else, return c

算法代码

java 示例代码

参考

MIT分析设计算法

在C语言中,到一组整中的最小k个可以采用多种算法实现,其中一种常见的方法是使用优先队列(通常称为堆),特别是大顶堆(Max Heap)。这里提供一个简单的示例,使用大顶堆结构: ```c #include <stdio.h> #include <stdlib.h> // 定义一个组大小 #define MAX_SIZE 100 // 结构体表示堆节点,包含值和索引 typedef struct { int value; int index; } MinHeapNode; // 大顶堆实现,用于存储前k小的元素 void max_heapify(int arr[], int n, int i) { int largest = i; // 初始化最大值位置为根节点 int left = 2 * i + 1; // 左孩子 int right = 2 * i + 2; // 右孩子 if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { // 如果有更大值 swap(&arr[i], &arr[largest]); // 交换 max_heapify(arr, n, largest); // 递归调整子树 } } // 建立大顶堆 void build_max_heap(int arr[], int k) { for (int i = k / 2 - 1; i >= 0; i--) { max_heapify(arr, k, i); } } // 添加新元素到堆并保持堆性质 void insert(int arr[], int n, int k, int new_val, int new_index) { arr[n++] = new_val; // 添加新元素 max_heapify(arr, k, n - 1); // 调整以保持堆 } // 获取最小k个 void get_min_k(int arr[], int k) { printf("The smallest %d numbers are:\n", k); for (int i = 0; i < k; i++) { printf("%d ", arr[0]); swap(&arr[0], &arr[k - 1]); // 将当前堆顶移到末尾 max_heapify(arr, k - 1, 0); // 更新堆 } } // 主函示例 int main() { int arr[] = {9, 8, 7, 6, 5, 4, 3, 2, 1}; int n = sizeof(arr) / sizeof(arr[0]), k = 3; build_max_heap(arr, k); // 创建初始堆 // 假设我们有新元素插入 insert(arr, n, k, 100, 10); // 新元素:100, 索引:10 get_min_k(arr, k); // 输出前k小 return 0; } ``` 在这个例子中,`build_max_heap()`函建立了一个大顶堆,`insert()`函用于添加新元素并维护堆属性,`get_min_k()`函则从堆中获取并删除最小的k个元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值