寻找最大的K个数,Top K问题的堆实现
2012-09-11 10:09
351 查看
寻找最大的K个数,如果所有的数据全部可以放入内存,就可以使用random select算法在线性时间内寻找第K大的数,再得到最大的K个数。
参考:/article/4790295.html
如果不能把所有数据的数据都一次性放入内存,就可以维护一个大小为K的堆,找最大的K个数,就维护一个小根堆,堆顶元素为这最大的K个数中的最小元素。具体实现参考下面两个例子:
2亿个整数中求最大的100万之和
题目:有一个文件中保存了2亿个整数,每个整数都以' '分隔。求最大的100万个整数之和。
算法:
1. 首先建立一个容量为100万(Top K)的int数组,从文件读取整数填充。
2. 利用堆维护该100万条记录(确保堆顶元素为最小值)
3. 从文件中读取一个整数与堆顶元素比较,如果大于堆顶元素则替换该元素,并调整堆的结构。
4. 重复步骤3一直到数据读取完
5. 将数组中的元素全部相加,得到结果
参考代码:
View Code
参考:http://blog.csdn.net/v_JULY_v/archive/2011/05/08/6403777.aspx
参考:/article/4790295.html
如果不能把所有数据的数据都一次性放入内存,就可以维护一个大小为K的堆,找最大的K个数,就维护一个小根堆,堆顶元素为这最大的K个数中的最小元素。具体实现参考下面两个例子:
2亿个整数中求最大的100万之和
题目:有一个文件中保存了2亿个整数,每个整数都以' '分隔。求最大的100万个整数之和。
算法:
1. 首先建立一个容量为100万(Top K)的int数组,从文件读取整数填充。
2. 利用堆维护该100万条记录(确保堆顶元素为最小值)
3. 从文件中读取一个整数与堆顶元素比较,如果大于堆顶元素则替换该元素,并调整堆的结构。
4. 重复步骤3一直到数据读取完
5. 将数组中的元素全部相加,得到结果
参考代码:
View Code
//copyright@yansha &&July //July、updated,2011.05.08 //题目描述: //搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的 //长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果 //除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门), //请你统计最热门的10个查询串,要求使用的内存不能超过1G。 #include <iostream> #include <string> #include <assert.h> using namespace std; #define HASHLEN 2807303 #define WORDLEN 30 // 结点指针 typedef struct node_no_space *ptr_no_space; typedef struct node_has_space *ptr_has_space; ptr_no_space head[HASHLEN]; struct node_no_space { char *word; int count; ptr_no_space next; }; struct node_has_space { char word[WORDLEN]; int count; ptr_has_space next; }; // 最简单hash函数 int hash_function(const char *p) { int value = 0; while (*p != '\0') { value = value * 31 + *p++; if (value > HASHLEN) value = value % HASHLEN; } return value; } // 添加单词到hash表 void append_word(const char *str) { int index = hash_function(str); ptr_no_space p = head[index]; while (p != NULL) { if (strcmp(str, p->word) == 0) { (p->count)++; return; } p = p->next; } // 新建一个结点 ptr_no_space q = new node_no_space; q->count = 1; q->word = new char [strlen(str)+1]; strcpy(q->word, str); q->next = head[index]; head[index] = q; } // 将单词处理结果写入文件 void write_to_file() { FILE *fp = fopen("result.txt", "w"); assert(fp); int i = 0; while (i < HASHLEN) { for (ptr_no_space p = head[i]; p != NULL; p = p->next) fprintf(fp, "%s %d\n", p->word, p->count); i++; } fclose(fp); } // 从上往下筛选,保持小根堆 void sift_down(node_has_space heap[], int i, int len) { int min_index = -1; int left = 2 * i; int right = 2 * i + 1; if (left <= len && heap[left].count < heap[i].count) min_index = left; else min_index = i; if (right <= len && heap[right].count < heap[min_index].count) min_index = right; if (min_index != i) { // 交换结点元素 swap(heap[i].count, heap[min_index].count); char buffer[WORDLEN]; strcpy(buffer, heap[i].word); strcpy(heap[i].word, heap[min_index].word); strcpy(heap[min_index].word, buffer); sift_down(heap, min_index, len); } } // 建立小根堆 void build_min_heap(node_has_space heap[], int len) { if (heap == NULL) return; int index = len / 2; for (int i = index; i >= 1; i--) sift_down(heap, i, len); } // 去除字符串前后符号 void handle_symbol(char *str, int n) { while (str < '0' || (str > '9' && str < 'A') || (str > 'Z' && str < 'a') || str > 'z') { str = '\0'; n--; } while (str[0] < '0' || (str[0] > '9' && str[0] < 'A') || (str[0] > 'Z' && str[0] < 'a') || str[0] > 'z') { int i = 0; while (i < n) { str[i] = str[i+1]; i++; } str[i] = '\0'; n--; } } int main() { char str[WORDLEN]; for (int i = 0; i < HASHLEN; i++) head[i] = NULL; // 将字符串用hash函数转换成一个整数并统计出现频率 FILE *fp_passage = fopen("string.txt", "r"); assert(fp_passage); while (fscanf(fp_passage, "%s", str) != EOF) { int n = strlen(str) - 1; if (n > 0) handle_symbol(str, n); append_word(str); } fclose(fp_passage); // 将统计结果输入文件 write_to_file(); int n = 10; ptr_has_space heap = new node_has_space [n+1]; int c; FILE *fp_word = fopen("result.txt", "r"); assert(fp_word); for (int j = 1; j <= n; j++) { fscanf(fp_word, "%s %d", &str, &c); heap[j].count = c; strcpy(heap[j].word, str); } // 建立小根堆 build_min_heap(heap, n); // 查找出现频率最大的10个单词 while (fscanf(fp_word, "%s %d", &str, &c) != EOF) { if (c > heap[1].count) { heap[1].count = c; strcpy(heap[1].word, str); sift_down(heap, 1, n); } } fclose(fp_word); // 输出出现频率最大的单词 for (int k = 1; k <= n; k++) cout << heap[k].count << " " << heap[k].word << endl; return 0; }
参考:http://blog.csdn.net/v_JULY_v/archive/2011/05/08/6403777.aspx
相关文章推荐
- 寻找最大的K个数,Top K问题的堆实现
- 寻找最大的k个数,TopK问题的C++实现
- 活动选择问题(活动安排问题)(最大数目活动选择问题)贪心算法C++实现
- 最大子数组问题分治法(递归)Java实现
- 最大子数组问题实现
- 求连续子数组最大和问题的两种解法_PHP实现
- [leetcode]分治法求解最大子序列问题——Java实现
- PHP实现求连续子数组最大和问题2种解决方法
- 基于堆实现的优先级队列:PriorityQueue 解决 Top K 问题
- 分治法解决寻找数组中最大最小值的问题
- 最大子数组问题-暴力求解-c++代码实现及运行实例结果
- 程序员编程艺术:第三章续、Top K算法问题的实现
- 寻找数组中的最大值最小值问题
- 10亿个数中找出最大的10000个数(top K问题)
- C++实现在一个字符串中寻找最大子串
- 最大子段和问题的分治实现和动态实现
- 无向图的最大割问题的实现
- SDAU 练习三 1001 寻找最大子序列问题(两种方法)
- 程序员编程艺术学习笔记(三续)Top K算法问题的实现
- 海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)