需求

从一亿个数据中,找出其中最小的10个数。

分析

最笨的方法就是将这一亿个数据,按从小到大进行排序,然后取前10个。这样的话,即使使用时间复杂度为nlogn的快排或堆排,由于元素会频繁的移动,效率也不会是最高的。

实际上我们可以维护一个大小为10的大顶堆,开始可以就将数列中的前10个数用来建堆,根元素最大。之后遍历剩余的数,分别将其与根元素进行比较,只要小于根元素,就将该数替代原来的根元素,成为新的根元素,之后adjustdown该堆,则该堆的根元素又是堆中最大的数据了。

测试代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> static void show(int *arr, int len)
{
int index;
for(index = 0; index < len; index++)
{
printf("%d ",arr[index]);
}
printf("\n");
} static void swap(int *left, int *right)
{
int tmp = *left;
*left = *right;
*right = tmp;
} void adjustdown(int *arr, int i, int end)
{
int key = arr[i];
int p = i;
int left = 2 * p + 1;
/* 越界就是没孩子 */ /* 只要能进循环,一定有左孩子 */
while( left <= end )
{
/* 有右孩子的情况下,大于等于左右孩子不用换 */
if( (key >= arr[left]) && (left+1 <= end && key >= arr[left+1]))
{
break;
}else if( key >= arr[left] && left + 1 > end) /* 没有右孩子,只有左孩子,且大于等于左孩子不用换*/
{
break;
}else if(left + 1 <= end && arr[left+1] >= arr[left] && key < arr[left+1]) /* 与右孩子换。要保证有右孩子,且右孩子大于等于左孩子,父亲小于右孩子 */
{
swap(arr+p, arr+left+1);
p = left + 1; //父亲与谁换,就到谁的位置了
left = 2 * p + 1;//父亲新的左孩子的位置
}else if(left + 1 <= end && arr[left] > arr[left + 1] && key < arr[left])/* 与左孩子换。有右孩子的情况下,右孩子小于左孩子,父亲小于左孩子 */
{
swap(arr + p, arr + left);
p = left;
left = 2 * p + 1;
}else if(left + 1 > end && arr[left] > key) /* 与左孩子换。没右孩子的情况下,只需父亲小于左孩子 */
{
swap(arr + p, arr + left);
p = left;
left = 2 * p + 1;
}
}
} void heap_sort(int *arr, int len)
{
int p; // 最后一个父亲
int end; // 最后一个有效下标
/* 建一个大顶堆,从最后一个父亲开始调 */
for(p = (len -1 -1) /2 ; p >= 0; p--)
{
adjustdown(arr, p ,len - 1);
}
/* 根结点的值最大,与末尾交换,并继续建立堆结构,再交换... */
for(end = len - 1; end >= 1; end--)
{
swap(arr, arr + end ); // end已经是最大值
adjustdown(arr,0,end-1); // 从arr+1 到 end-1位置都是满足堆结构的
}
} void my_top(int *arr, int len, int top, int *arr_top, int top_len) //此处选最小的top个数,维护大堆。如果是最大top个数,就维护小堆。
{
/* 开始用插入排序 */ /* 不用插入排序,对arr_top直接建堆也是可以的 */
int index;
int pos;
for(index = 0; index < len; index ++)
{
if(index < top)
{
if(index == 0)
{
arr_top[index] = arr[index];
}else
{
/* 插入排序 */
//int pos; 从大到小
for(pos = index - 1; pos >= 0; pos--)
{
if(arr[index] >= arr_top[pos])
{
arr_top[pos + 1] = arr_top[pos];
}else
{
break;
}
}
arr_top[pos+1] = arr[index];
}
}else
{
if(arr[index] >= arr_top[0]) //比最大值还大,说明不是最小的10个数
{
continue;
}else
{
arr_top[0] = arr[index]; //淘汰掉原来最大的
adjustdown(arr_top,0,top_len-1); //重新选最大值 复杂度nlogn 但是这10个数并不是有序的
}
}
}
} int main(int argc, char *argv[])
{
int index;
int arr[20];
int arr_top[5];
memset(arr,0,20);
srand(time(NULL));
for(index = 0; index < 20; index++)
{
arr[index] = rand()%50+1;
}
show(arr,20); heap_sort(arr,20);
show(arr,20); my_top(arr,20,5,arr_top,5);
show(arr_top,5); system("pause");
return 0;
}

百度面试题——top K算法的更多相关文章

  1. 百度面试题——top K算法

    需求 从一亿个数据中,找出其中最小的10个数. 分析 最笨的方法就是将这一亿个数据,按从小到大进行排序,然后取前10个.这样的话,即使使用时间复杂度为nlogn的快排或堆排,由于元素会频繁的移动,效率 ...

  2. 程序员编程艺术:第三章续、Top K算法问题的实现

    程序员编程艺术:第三章续.Top K算法问题的实现 作者:July,zhouzhenren,yansha.     致谢:微软100题实现组,狂想曲创作组.     时间:2011年05月08日    ...

  3. Top K 算法详解

    http://xingyunbaijunwei.blog.163.com/blog/static/7653806720111149318357/ 问题描述         百度面试题:        ...

  4. Top K算法

    应用场景: 搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节.        假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果 ...

  5. hihoCoder 1133 二分·二分查找之k小数(TOP K算法)

    #1133 : 二分·二分查找之k小数 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回里我们知道Nettle在玩<艦これ>,Nettle的镇守府有很 ...

  6. 使用堆实现Top K 算法 JS 实现

    1. 堆算法Top,时间复杂度 O(LogN) function top(arr,comp){ if(arr.length == 0){return ;} var i = arr.length / 2 ...

  7. top k 算法

    对于一个非有序的数组A[p..r],求数组中第k小的元素. 如何考虑 排序(部分排序)就不用说了..o(nlgn),当然如果在实际情况中要一直取值,当然要排序后,一次搞定,以后都是O(1) 我们这里提 ...

  8. Top K问题-BFPRT算法、Parition算法

    BFPRT算法原理 在BFPTR算法中,仅仅是改变了快速排序Partion中的pivot值的选取,在快速排序中,我们始终选择第一个元素或者最后一个元素作为pivot,而在BFPTR算法中,每次选择五分 ...

  9. 04Top K算法问题

    本章阐述寻找最小的k个数的反面,即寻找最大的k个数,尽管寻找最大的k个树和寻找最小的k个数,本质上是一样的.但这个寻找最大的k个数的问题的实用范围更广,因为它牵扯到了一个Top K算法问题,以及有关搜 ...

随机推荐

  1. python学习总结---网络编程

    网络编程 相关概念 - OSI七层模型:它从低到高分别是:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. - TCP/IP: 在OSI七层模型基础上简化抽象出来的一套网络协议簇,现在得到 ...

  2. LeetCode - 1. Two Sum(8ms)

    Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...

  3. 对 vscode 自动格式化的结果不太满意,我们该如何自己调整直至自己满意为止

    前提概述 采用vue-cli 3.0自动生成vue项目,选了ESlint+Prettier,在写request.js的时候,顺手用vscode右击格式化文件(Alt+Shift+F),一下子报了8个问 ...

  4. LeetCode 21 ——合并两个有序链表

    1. 题目 2. 解答 新建一个带有哨兵结点的链表,依次比较两个有序链表的结点值,将较小值的结点插入到新链表后面.直到其中一个比较完毕,将另一个链表剩余的结点全部放到新链表最后面即可.最后,可以删除哨 ...

  5. mac下使用clion构建boost库

    mac下使用clion构建boost库 使用brew install boost 完成后发现boost被安装在在/usr/local/Cellar/boost下 jetbrain给出的指导意见 htt ...

  6. Linux SPI总线和设备驱动架构之二:SPI通用接口层

    通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了 ...

  7. libevent显式调用事件处理

    ) { SearchAcceptListen2(p_ev_arg->listen_fd,,&notify_event,base); event_base_loop(base, EVLOO ...

  8. const在c/c++中的区别

    #include <iostream> using namespace std; int main() { ; ; }; ; i < sizeof array / sizeof *a ...

  9. lintcode-62-搜索旋转排序数组

    62-搜索旋转排序数组 假设有一个排序的按未知的旋转轴旋转的数组(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2).给定一个目标值进行搜索,如果在数组中找到目标值返回数组中的索引 ...

  10. Windows IRP

    IRP(I/O Request Packet),是由IO manager发起的对device的IO请求. 当用户调用系统API,如createFile类似的函数,其实是会交给IO manager来做相 ...