有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词.

#include<iostream>
#include<string>
using namespace std;

#define FILE_NUM 10
#define WORDLEN 30
#define HASHLEN 7303

typedef struct node_no_space{
	char *word;
	int count;
	struct node_no_space *next;
}node_no_space, *p_node_no_space;

typedef struct node_has_space{
	char word[WORDLEN];
	int count;
	struct node_has_space *next;
}node_has_space, *p_node_has_space;

p_node_no_space bin[HASHLEN] = {NULL}; 

void swap(int *a, int *b) {
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

unsigned int hash(char *p_word) {
	unsigned int index = 0;
	while(*p_word) {
		index += index * 31 + *p_word;
		p_word++;
	}
	return index % HASHLEN;
}

int trim_word(char *word) {
	int n = strlen(word) - 1;
	int i = 0;
	if(n < 0)
		return 0;
	while(word[n] < '0' || (word[n] > '9' && word[n] < 'A') || (word[n] > 'Z' && word[n] < 'a') || word[n] > 'z') {
		word[n] = '\0';
		n--;
	}
	if(n < 0)
		return 0;
	while(word[i] < '0' || (word[i] > '9' && word[i] < 'A') || (word[i] > 'Z' && word[i] < 'a') || word[i] > 'z') {
		i++;
	}
	strcpy(word, word + i);
	return 1;
}

void insert_word(char *p_word) {
	unsigned int index = hash(p_word);
	node_no_space *p;
	for(p = bin[index]; p != NULL; p = p->next) {
		if(strcmp(p_word, p->word) == 0) {
			(p->count)++;
			return;
		}
	}

	p = (node_no_space*)malloc(sizeof(node_no_space));
	p->count = 1;
	p->word = (char*)malloc(strlen(p_word) + 1);
	strcpy(p->word, p_word);
	p->next = bin[index];
	bin[index] = p;
}

void min_heap(node_has_space *heap, int i, int len) {
	int left = 2 * i;
	int right = 2 * i + 1;
	int min_index = 0;

	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[min_index].count, &heap[i].count);
		char buffer[WORDLEN];
		strcpy(buffer, heap[min_index].word);
		strcpy(heap[min_index].word, heap[i].word);
		strcpy(heap[i].word, buffer);
		min_heap(heap, min_index, len);
	}
}

void build_min_heap(node_has_space *heap, int len) {
	int index = len / 2;
	int i;
	for(i = index; i >= 1; i--) {
		min_heap(heap, i, len);
	}
}

void destroy_bin() {
	node_no_space *p, *q;
	int i = 0;
	while(i < HASHLEN) {
		p = bin[i];
		while(p) {
			q = p->next;
			if(p->word) {
				free(p->word);
				p->word = NULL;
			}
			free(p);
			p = NULL;
			p = q;
		}
		bin[i] = NULL;
		i++;
	}
}

void write_to_file(char *path) {
	FILE *out;
	if((out = fopen(path, "w")) == NULL) {
		cout << "error, open " << path << " failed!" << endl;
		return;
	}
	int i;
	node_no_space *p;
	i = 0;
	while(i < HASHLEN) {
		for(p = bin[i]; p != NULL; p = p->next) {
			fprintf(out, "%s %d\n", p->word, p->count);
		}
		i++;
	}
	fclose(out);
	destroy_bin();
}

void main() {
	char word[WORDLEN];
	char path[20];
	int count;
	int n = 10;
	unsigned int index = 0;
	int i;
	FILE *fin[10];
	FILE *fout;
	FILE *f_message;
	node_has_space *heap = (node_has_space*)malloc(sizeof(node_has_space) * (n + 1));
	// divide word into n files
	if((f_message = fopen("words.txt", "r")) == NULL) {
		cout << "error, open source file failed!" << endl;
		return;
	}
	for(i = 0; i < n; i++) {
		sprintf(path, "tmp%d.txt", i);
		fin[i] = fopen(path, "w");
	}
	while(fscanf(f_message, "%s", word) != EOF) {
		if(trim_word(word)) {
			index = hash(word) % n;
			fprintf(fin[index], "%s\n", word);
		}
	}
	for(i = 0; i < n; i++) {
		fclose(fin[i]);
	}
	// do hash count
	for(i = 0; i < n; i++) {
		sprintf(path, "tmp%d.txt", i);
		fin[i] = fopen(path, "r");
		while(fscanf(fin[i], "%s", word) != EOF) {
			insert_word(word);
		}
		fclose(fin[i]);
		write_to_file(path);
	}
	// heap find 
	for(i = 1; i <= n; i++) {
		strcpy(heap[i].word, "");
		heap[i].count = 0;
	}
	build_min_heap(heap, n);
	for(i = 0; i < n; i++) {
		sprintf(path, "tmp%d.txt", i);
		fin[i] = fopen(path, "r");
		while(fscanf(fin[i], "%s %d", word, &count) != EOF) {
			if(count > heap[1].count) {
				heap[1].count = count;
				strcpy(heap[1].word, word);
				min_heap(heap, 1, n);
			}
		}
		fclose(fin[i]);
	}

	for(i = 1; i <= n; i++)
		cout << heap[i].word << ":" << heap[i].count << endl;
}

首先,我们看到这个题目应该做一下计算,大概的计算,因为大家都清楚的知道1G的文件不可能用1M的内存空间处理。所以我们要按照1M的上线来计算,假设每个单词都为16个字节,那么1M的内存可以处理多少个单词呢? 1M = 1024 KB = 1024 * 1024 B 。然后1M / 16B = 2^16个单词,那么1G大概有多少个单词呢? 有2^26个单词,但是实际中远远不止这些,因为我们是按照最大单词长度算的。我们需要把这1G的单词分批处理,根据上面的计算,可以分成大于2^10个文件。索性就分成2000个文件吧,怎么分呢,不能随便分,不能简单的按照单词的顺序然后模2000划分,因为这样有可能相同的单词被划分到不同的文件中去了。这样在统计个数的时候被当成的不同的单词,因为我们没有能力把在不同文件中相同单词出现的次数跨越文件的相加,这就迫使我们要把不同序号的同一个单词划分到同一个文件中:应用hash统计吧。稍后代码会给出方法。然后呢,我们队每个文件进行分别处理。按照key-value的方法处理每个单词,最终得出每个文件中包含每个单词和单词出现的次数。然后再建立大小为100的小根堆。一次遍历文件进行处理。我没有弄1G的文件,弄1M的,简单的实现了一下,不过原理就是这样的。这是单词: http://download.csdn.net/detail/zzran/4934173


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值