100w 个整数里取出最大的 500 个, 可以转换为 n 个数里取出最大的 m 个

/**
 * 100w 个整数里取出最大的 500 个:
 * 可以转换为 n 个数里取出最大的 m 个,其中 m < n,采用堆排序实现,时间复杂度为 n + nlogm
 * 举例:12 20 9 18 7 14 几个数中取出最大的三个:
 * 做法:遍历所需计算的整数。创建一个节点数为3的最小堆,当堆装满后,再来的数与根节点对比,如果比根节点大,替换,然后再走到根节点相应的位置,图例如下:
 *         (0)        (1)       (2)       (3)       (4)        (5)      (6)        (7)        (8)
 *         12         12        12         12        9          18        12        7 丢弃      14
 *                   /         /  \       / \      /  \       /  \      /  \                  /   *                  20        20   9     9  20    12  20     12  20    18  20                18  20
 * 希望读者有更好方法的不吝赐教
 */
#include<stdio.h>
#define LENGTH(s) (sizeof(s) / sizeof(s[0]))  //取数组长度 define  不是定义数组,而是把一段代码取一个别名
/**
 * 交换两个整数
 */
void swap(int *a, int *b){
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

/**
 * 将节点与其子节点对比,如果比子节点大,则与其交换,替换完了再保证被替换的同节点比右边的弟兄节点小,否则左右兄弟节点交换
 */
int shift_down(int *r, int i){
    if( i >= LENGTH(r) ) return i;
    int left, right, last_left;
    left = 2 * i +1;
    // 如果节点比左了节点大,交换,如注释中第(6)步
    if( r[i] > r[left] ){
        swap(&r[i], &r[left]);
        last_left = shift_down(r, left);
        // 如果右节点存在,左右对比,保证左节点比右节点小,如注释中第(3)步
        if( last_left <= sizeof(r) - 2 ){
            if(r[last_left] > r[last_left+1])
                swap(&r[last_left], &r[last_left+1]);
        }
        return 0;
    }else{
        return i;
    }
}
/**
 * 判断节点是否为右节点
 */
int is_right(int i){
    return (i > 0) && ( (i -1) % 2 == 1);
}
/**
 * 将节点与父节点对比,如果比爷节点大,则民其交换,替换完再保证左节点始终比右节点小
 */
int shift_up(int *r, int i){
    if( i <= 0 ) return i;
    int parent;
    parent = (i -1) / 2;
    if(r[parent] > r[i]){
        swap(&r[parent], &r[i]);
        shift_up(r, parent);
    }
    return 0;
}
int main(){
    int r_size = 3; // 取出结果数
    int arr[8] = {12, 20, 9, 18, 7, 14, 21, 28};  //待处理数组
    int r[r_size];
    int arr_size, i = 0, result_size = 0;
    arr_size = LENGTH(arr);
    for( i = 0; i < arr_size; i++ ){
        //判断结果堆是否满,未满直接加上,若满与第一个对比
        if( result_size >= r_size ){
            if( arr[i] > r[0] ){
                //替换根节点,如注释中第(5)步
                r[0] = arr[i];
                // 调整位置,将最小位置到根节点,如注释中第(6)步
                shift_down(r, 0);
            }
        }else{
            // 如果根节点还没填满,在节点末插入一个新节点
            r[result_size] = arr[i];
            // 如果是右节点,与左节点对比,如果比左节点小,左右交换
            if( is_right(result_size) && r[result_size] < r[result_size-1] )
                swap(&r[result_size], &r[result_size-1]);
            shift_up(r, result_size);
            result_size ++;
        }
    }
    for(i = 0; i < r_size; i++){
        printf("\n %d: %d", i, r[i]);
    }
    return 0;
}

时间: 2024-08-30 08:10:34

100w 个整数里取出最大的 500 个, 可以转换为 n 个数里取出最大的 m 个的相关文章

iPhone5S掉水盆里了不开机了维修多少钱iPhone5S掉水里开不开机了维修多少钱

为什么网上的价格差距这么大?为什么打电话问的商家报的价格都不一样?哪种几百块钱的屏幕(芯片)能相信吗?淘宝上面的屏幕(芯片)能相信吗?哪里能找到原装的屏幕呢?哪里的维修点才靠谱呢?北京中关村和深圳那边的维修市场能相信吗? 电子城报的二三百能相信吗?原装的配件和仿的价钱相差多少呢? 当您看到了这里,请您选择飞维智能科技有限责任公司(我们用最真挚的态度来为您服务) 我们在保证质量的前提下用最低的价格来为广大客户服务.我们的原则是(少花钱,买放心,保质量,求口碑) 工程师:罗飞报修热线:158 110

校招试题 n个数里最小的k个 stringstream运用

找出n个数里最小的k个 输入描述: 每个测试输入包含空格分割的n+1个整数,最后一个整数为k值,n 不超过100. 输出描述: 输出n个整数里最小的k个数.升序输出 输入例子1: 3 9 6 8 -10 7 -11 19 30 12 23 5 输出例子1: -11 -10 3 6 7 #include<bits/stdc++.h> using namespace std; const int maxn = 110; int num[maxn]; int i=0; string s; strin

在ASP.NET2.0里打印网页指定的内容(比如打印网页里的一个Table)

原文:在ASP.NET2.0里打印网页指定的内容(比如打印网页里的一个Table) 打印指定内容: <html> <head> <script   type= "text/javascript "   language= "javascript "> function   printPage()   {   var   newWin   =   window.open( 'about:blank ', ' ', ' ');   v

【C语言】输入一个整数,输出该数二进制表示中1的个数(三种方法)

输入一个整数,输出该数二进制表示中1的个数.如输入32,输出1. 代码实现: 方法1:与运算 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; int FindOneNumber(unsigned int num) {     int numberofOne = 0;     while (num)     {         num = num & (num - 1);         

22、输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路: n &(n-1)把n的最右边的1去掉,用count++计算1的个数  eg: 101 & 100 = 100   1 class Solution { 2 public: 3 int NumberOf1(int n) { 4 int count = 0; 5             while(n!=0){ 6                 count++; 7                 n = n&

快速排序里的学问:从猜数字开始 猜数字里的算法思想

我们先来玩一个猜数字游戏: 我心里默念一个1~64之间的数,你来猜(你只能问答案是“是”或“否”的问题).为了保证不论在什么情况下都能以尽量少的次数猜中,你应该采取什么策略呢? 很显然,二分.先是猜是不是位于1~32之间,排除掉一半可能性,然后对区间继续二分.这种策略能够保证无论数字怎么跟你捉迷藏,都能在log2n次以内猜中.用算法的术语来说就是它的下界是最好的.(算法的下界 :一个问题的下界是用来解决该问题的任意算法所需要的最小时间复杂度. ) 我们再来回顾一下这个游戏所蕴含的本质:为什么这种

用vector或者set删除一亿个数里的奇数

如何用vector或者set删除一亿个数里的奇数 先说说VECTOR怎么删除指定的元素,因为VECTOR有迭代器失效的问题,一般人都会写这么样的一个函数 for(vector<int>::itertor it=a.begin();it!=a.end();) { if(a[i]%2==1) it=a.erase(it); else it++; } 这样的函数如果数据量很小的话基本没有什么问题,但是如果数据量是1个亿,那么你得要运行1天的时间才能完全删除掉,这是因为VECTOR要动态调整,还要收缩

剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)

1. 题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 2. 思路和方法 使用移位(<<)和 “| & !”操作来实现.1的二进制是:前面都是0,最后一位为1.每次向左移位一下,使得flag的二进制表示中始终只有一个位为1,每次与n做位与操作,这样就相当于逐个检测n的每一位是否是1.unsigned int flag = 1; 3. C++核心代码 3.1 位运算 1 class Solution { 2 public: 3 int NumberOf1(int

HTML中head里的内容经浏览器解析后全到body里

我从linux服务器nginx上把一个网站迁移到windows的IIS上数据什么的都么有问题,配置好rewrite以后,访问网站,发现样式变动了,网站上方空出了一块我用chrome浏览器的审查元素一看,发现head里的内容全到Body里了,而且body的最开始出多出了一块带引号的空白! 但是如果右键查看源代码的话,代码是正确的,没有问题! 正常状态 错误状态 是include的问题,包含的文件是utf-8编码的,但是有BOM头,我用一个函数把网站目录里的所有文件的BOM头去掉以后就恢复正常了,希