`
kenby
  • 浏览: 723776 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

寻找最大的K个数 (C语言实现)

阅读更多

题目: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个数

    ### 寻找最大的K个数的关键知识点解析 #### 一、问题背景与基本思路 在IT面试场景中,“寻找最大的K个数”是一个常见的算法题目。该问题要求从大量无序数字中找到最大的K个数。这个问题看似简单,但实际上包含了多...

    k-medoids C源代码_C语言_k-medoids_

    本篇文章将深入探讨k-medoids算法的原理、C语言实现及其在实际应用中的价值。 k-medoids算法基于代表对象(medoids)的概念,而非k-means中的质心(centroids)。在k-medoids中,每个聚类的中心是实际存在的数据点...

    k-means聚类算法c语言实现

    通过阅读和理解这些代码,你可以深入学习k-means算法的C语言实现细节,同时也可以了解如何处理基因表达数据。这个实现可以帮助你理解数据聚类的基本原理,并且可以在其他领域如图像分割、市场细分等应用中进行类似的...

    高斯列主元消去法C语言实现

    // 寻找最大主元并交换 int max_idx = k; for (int j = k + 1; j ; j++) if (fabs(A[j][k]) &gt; fabs(A[max_idx][k])) max_idx = j; // 交换行 // ...交换代码... // 行减法 for (int i = k + 1; i ; i++) ...

    最大独立集 C语言

    如果一个图的最小着色数为k,则其最大独立集大小至少为n/k(n为图的节点数)。因此,通过优化图着色算法,我们也能为最大独立集问题提供一定的启发。 在实际应用中,最大独立集问题广泛出现在社交网络分析、无线...

    Dijkstra算法_C语言实现代码

    - `#define MAX_NODES 1024`:定义最大节点数,这里假设图中的节点数量不会超过1024个。 - `int n, dist[MAX_NODES][MAX_NODES];`:`n`存储实际的节点数量,`dist[][]`数组用于存储图中任意两个节点之间的距离。 ##...

    c语言实现单纯形法

    ### c语言实现单纯形法 #### 运筹学中的单纯形法 单纯形法是运筹学中一种求解线性规划问题的经典算法。通过迭代的方式寻找最优解,该方法适用于处理具有多个变量和约束条件的优化问题。下面将根据提供的代码片段...

    music_c语言music算法_C语言_musicdoac++_MUSIC算法_C语言DOA算法

    4. **噪声子空间与信号子空间分离**:将特征向量按照对应的特征值大小排序,前k个对应最大特征值的特征向量组成信号子空间,其余的组成噪声子空间,其中k是阵列中传感器的数量减去源的数量。 5. **谱峰搜索**:构造...

    kmeans算法c语言实现,能对不同维度的数据进行聚类

    总结来说,这个C语言实现的K-means算法能够处理任意维度的数据,并且支持用户自定义的聚类数量k。其优点在于高效、灵活,适用于各种环境,尤其是资源受限的情况。通过阅读和理解`kmeans.c`源代码,我们可以深入学习K...

    牛顿下山法 c语言实现

    ### 牛顿下山法 C语言实现解析 #### 核心知识点概述 本文将深入解析一个C语言程序,该程序旨在解决线性方程组问题,并非“牛顿下山法”。程序通过高斯消元法求解线性方程组,其中包含几个关键函数:`input`用于从...

    kmens+遗传算法的C语言实现

    【标题】"kmens+遗传算法的C语言实现" 涉及到的主要知识点是遗传算法和k-means聚类算法在C语言环境中的编程实现。这两种算法在数据挖掘和机器学习领域中都有广泛的应用。 【遗传算法】是一种受到生物进化论启发的...

    木棒三角形 C语言实现 枚举算法

    根据给定的信息,本文将详细解释“木棒三角形 C语言实现 枚举算法”这一主题,特别是如何通过枚举算法在C语言中求解直角三角形的最大面积。 ### 一、问题背景 题目要求从给定的一组正整数(长度不超过100)中找出...

    C语言的KD树实现 kdtree

    在`kdtree-0.5`这个压缩包中,可能包含了KD树的C语言实现源代码,包括节点定义、构建、查询、插入和删除等函数,以及相关的示例和测试用例。通过阅读和理解这些代码,可以深入学习KD树的实现原理和应用技巧。

    c语言最大流最小费用

    根据给定的信息,本文将对...本文通过对C语言实现的最大流最小费用算法的分析,介绍了最大流最小费用问题的基本概念、解决方法以及具体的实现细节。通过理解这些知识点,可以更好地掌握此类问题的求解方法和技术要点。

    一个声音模块的C语言实现

    ### 一个声音模块的C语言实现 #### 一、引言 随着科技的进步,家用电器种类日益增多,人们越来越追求便捷的生活方式。如果能够通过语音控制各种家电的开关,无疑会给生活带来极大的便利。为此,李萍和姚竞红设计并...

    各种排序算法C语言实现

    随机化选择是寻找数组中第k小(或第k大)元素的算法,可以看作是快速选择的变种,通过随机化选择枢轴元素来提高性能。 9. **快速排序的递归版与非递归版**: 如前所述,递归版使用了函数递归,而非递归版使用循环...

    C语言6种排序算法及其实现

    以下将详细阐述标题和描述中提到的6种排序算法及其C语言实现。 1. 冒泡排序(Bubble Sort): 冒泡排序是一种简单的排序算法,通过重复遍历数组,比较相邻元素并根据需要交换它们来实现排序。它保证了相同元素的...

    用 C语言实现和改进银行家算法

    ### 使用C语言实现和改进银行家算法 #### 1. 引言 在现代计算机系统中,资源管理和分配是一项至关重要的任务。为了确保系统能够高效、稳定地运行,需要采用有效的算法来避免诸如死锁等问题的发生。其中,“银行家...

    c语言入门编程之数组操作子数组最大平均数.zip

    计算数组的平均数需要先求和再除以元素个数: ```c float avg; int sum = 0; for(int i = 0; i 数组长度; i++) { sum += nums[i]; } avg = (float)sum / 数组长度; ``` 4. **寻找子数组最大平均数** 要...

    《你必须知道的495个C语言问题》

    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= ...

Global site tag (gtag.js) - Google Analytics