题目:100亿个整数,求最大的1万个数,并说出算法的时间复杂度
算法:如果把100亿个数全部读入内存,需要100 0000 0000 * 4B 大约40G的内存,这显然是不现实的。
我们可以在内存中维护一个大小为10000的最小堆,每次从文件读一个数,与最小堆的堆顶元素比较,若比堆顶元素大,
则替换掉堆顶元素,然后调整堆。最后剩下的堆内元素即为最大的1万个数,算法复杂度为O(NlogN)
实现:从文件读数据有讲究,如果每次只读一个数,效率太低,可以维护一个输入缓冲区,一次读取一大块数据到内存,
用完了又从文件接着读,这样效率高很多,缓冲区的大小也有讲究,一般要设为4KB的整数倍,因为磁盘的块大小一般
就是4KB
/* 编译 gcc main.c
* 产生测试数据: dd if=/dev/urandom of=random.dat bs=1M count=1024
* 运行: ./a.out random.dat 100
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
static unsigned int BUF_PAGES; /* 缓冲区有多少个page */
static unsigned int PAGE_SIZE; /* page的大小 */
static unsigned int BUF_SIZE; /* 缓冲区的大小, BUF_SIZE = BUF_PAGES*PAGE_SIZE */
static int *buffer; /* 输入缓冲区 */
static int *heap; /* 最小堆 */
long get_time_usecs();
void init_heap(int n);
void adjust(int n, int i);
int main(int argc, char **argv)
{
unsigned int K, idx, length;
int fd, i, bytes, element;
long start_usecs = get_time_usecs();
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
printf("can't open file %s\n",argv[1]);
exit(0);
}
PAGE_SIZE = 4096; /* page = 4KB */
BUF_PAGES = 512;
BUF_SIZE = PAGE_SIZE*BUF_PAGES; /* 4KB*512 = 2M */
buffer = (int *)malloc(BUF_SIZE);
if (buffer == NULL) exit(0);
K = atoi(argv[2]);
heap = (int *)malloc(sizeof(int)*(K+1));
if (heap == NULL) {
free(buffer);
exit(0);
}
bytes = read(fd, heap+1, K*sizeof(int));
if (bytes < K*sizeof(int)) {
printf("data size is too small\n");
exit(0);
}
init_heap(K);
idx = length = 0;
for (;;) {
if (idx == length) { /* 输入缓冲区用完 */
bytes = read(fd, buffer, BUF_SIZE);
if (bytes == 0) break;
length = bytes/4;
idx = 0;
}
//从buffer取出一个数,若比最小堆堆顶元素大,则替换之
element = buffer[idx++];
if (element > heap[1]) {
heap[1] = element;
adjust(K, 1);
}
}
long end_usecs = get_time_usecs();
printf("the top %d numbers are: \n", K);
for (i = 1; i <= K; i++) {
printf("%d ", heap[i]);
if (i % 6 == 0) {
printf("\n");
}
}
printf("\n");
free(buffer);
free(heap);
close(fd);
double secs = (double)(end_usecs - start_usecs) / (double)1000000;
printf("program tooks %.02f seconds.\n", secs);
return 0;
}
void init_heap(int n)
{
int i;
for (i = n/2; i > 0; i--) {
adjust(n, i);
}
}
/* 节点i的左子树和右子树已是最小堆, 此函数的
* 作用是把以节点i为根的树调整为最小堆 */
void adjust(int n, int i)
{
heap[0] = heap[i];
i <<= 1;
while (i <= n) {
if (i < n && heap[i+1] < heap[i]) {
i++;
}
if (heap[i] >= heap[0]) {
break;
}
heap[i>>1] = heap[i];
i <<= 1;
}
heap[i>>1] = heap[0];
}
long get_time_usecs()
{
struct timeval time;
struct timezone tz;
memset(&tz, '\0', sizeof(struct timezone));
gettimeofday(&time, &tz);
long usecs = time.tv_sec*1000000 + time.tv_usec;
return usecs;
}
测试和运行: 见代码的注释,主要是如何产生测试数据,
linux提供了一个产生测试数据的命令,直接调用就行了
dd if=/dev/urandom of=random.dat bs=1M count=1024
这样产生的测试数据是二进制的,我们把美4个字节当成1个整数来用。
分享到:
相关推荐
### 寻找最大的K个数的关键知识点解析 #### 一、问题背景与基本思路 在IT面试场景中,“寻找最大的K个数”是一个常见的算法题目。该问题要求从大量无序数字中找到最大的K个数。这个问题看似简单,但实际上包含了多...
本篇文章将深入探讨k-medoids算法的原理、C语言实现及其在实际应用中的价值。 k-medoids算法基于代表对象(medoids)的概念,而非k-means中的质心(centroids)。在k-medoids中,每个聚类的中心是实际存在的数据点...
通过阅读和理解这些代码,你可以深入学习k-means算法的C语言实现细节,同时也可以了解如何处理基因表达数据。这个实现可以帮助你理解数据聚类的基本原理,并且可以在其他领域如图像分割、市场细分等应用中进行类似的...
// 寻找最大主元并交换 int max_idx = k; for (int j = k + 1; j ; j++) if (fabs(A[j][k]) > fabs(A[max_idx][k])) max_idx = j; // 交换行 // ...交换代码... // 行减法 for (int i = k + 1; i ; i++) ...
如果一个图的最小着色数为k,则其最大独立集大小至少为n/k(n为图的节点数)。因此,通过优化图着色算法,我们也能为最大独立集问题提供一定的启发。 在实际应用中,最大独立集问题广泛出现在社交网络分析、无线...
- `#define MAX_NODES 1024`:定义最大节点数,这里假设图中的节点数量不会超过1024个。 - `int n, dist[MAX_NODES][MAX_NODES];`:`n`存储实际的节点数量,`dist[][]`数组用于存储图中任意两个节点之间的距离。 ##...
### c语言实现单纯形法 #### 运筹学中的单纯形法 单纯形法是运筹学中一种求解线性规划问题的经典算法。通过迭代的方式寻找最优解,该方法适用于处理具有多个变量和约束条件的优化问题。下面将根据提供的代码片段...
4. **噪声子空间与信号子空间分离**:将特征向量按照对应的特征值大小排序,前k个对应最大特征值的特征向量组成信号子空间,其余的组成噪声子空间,其中k是阵列中传感器的数量减去源的数量。 5. **谱峰搜索**:构造...
总结来说,这个C语言实现的K-means算法能够处理任意维度的数据,并且支持用户自定义的聚类数量k。其优点在于高效、灵活,适用于各种环境,尤其是资源受限的情况。通过阅读和理解`kmeans.c`源代码,我们可以深入学习K...
### 牛顿下山法 C语言实现解析 #### 核心知识点概述 本文将深入解析一个C语言程序,该程序旨在解决线性方程组问题,并非“牛顿下山法”。程序通过高斯消元法求解线性方程组,其中包含几个关键函数:`input`用于从...
【标题】"kmens+遗传算法的C语言实现" 涉及到的主要知识点是遗传算法和k-means聚类算法在C语言环境中的编程实现。这两种算法在数据挖掘和机器学习领域中都有广泛的应用。 【遗传算法】是一种受到生物进化论启发的...
根据给定的信息,本文将详细解释“木棒三角形 C语言实现 枚举算法”这一主题,特别是如何通过枚举算法在C语言中求解直角三角形的最大面积。 ### 一、问题背景 题目要求从给定的一组正整数(长度不超过100)中找出...
在`kdtree-0.5`这个压缩包中,可能包含了KD树的C语言实现源代码,包括节点定义、构建、查询、插入和删除等函数,以及相关的示例和测试用例。通过阅读和理解这些代码,可以深入学习KD树的实现原理和应用技巧。
根据给定的信息,本文将对...本文通过对C语言实现的最大流最小费用算法的分析,介绍了最大流最小费用问题的基本概念、解决方法以及具体的实现细节。通过理解这些知识点,可以更好地掌握此类问题的求解方法和技术要点。
### 一个声音模块的C语言实现 #### 一、引言 随着科技的进步,家用电器种类日益增多,人们越来越追求便捷的生活方式。如果能够通过语音控制各种家电的开关,无疑会给生活带来极大的便利。为此,李萍和姚竞红设计并...
随机化选择是寻找数组中第k小(或第k大)元素的算法,可以看作是快速选择的变种,通过随机化选择枢轴元素来提高性能。 9. **快速排序的递归版与非递归版**: 如前所述,递归版使用了函数递归,而非递归版使用循环...
以下将详细阐述标题和描述中提到的6种排序算法及其C语言实现。 1. 冒泡排序(Bubble Sort): 冒泡排序是一种简单的排序算法,通过重复遍历数组,比较相邻元素并根据需要交换它们来实现排序。它保证了相同元素的...
### 使用C语言实现和改进银行家算法 #### 1. 引言 在现代计算机系统中,资源管理和分配是一项至关重要的任务。为了确保系统能够高效、稳定地运行,需要采用有效的算法来避免诸如死锁等问题的发生。其中,“银行家...
计算数组的平均数需要先求和再除以元素个数: ```c float avg; int sum = 0; for(int i = 0; i 数组长度; i++) { sum += nums[i]; } avg = (float)sum / 数组长度; ``` 4. **寻找子数组最大平均数** 要...
3.15 我要检查一个数是不是在另外两个数之间,为什么if(a b c)不行? 40 3.16 为什么如下的代码不对?int a=1000, b=1000; long int c=a * b; 40 3.17 为什么下面的代码总是给出0?double degC, degF; degC= ...