转载请注明出处:http://blog.csdn.net/mxway/article/details/21321541

在搜索引擎在通常会对关键字出现的次数进行统计,这篇文章分析下使用C++ STL中的map进行统计,及使用字典树进行统计在运行速度,空间及适用场合进行分析。首先随机生成100万个3-6长度的字符串。为了简化问题,字符串中仅由小写字母组成。另外随机生成10万个长度3-8的字符串用于测试map和字典树在查询方面的效率。

下面是使用map和字典树实现的C++代码:

STL map实现统计的源码:

#include<iostream>
#include<ctime>
#include<fstream>
#include<string>
#include<map>
using namespace std;

int main()
{
	clock_t start,end;
	map<string,int> dict;
	string word;
	ifstream in("data.dat");
	start = clock();
	while(in>>word)
	{
		if(dict[word])
		{
			dict[word] = 1;
		}
		else
		{
			dict[word]++;
		}
	}
	in.close();
	end = clock();
	cout<<"STL MAP统计花费的时间为:"<<end-start<<"毫秒"<<endl;
	map<string,int>::iterator itr = dict.begin();
	start = clock();
	ofstream out("out.txt");
	while(itr != dict.end() )
	{
		out<<itr->first<<" "<<itr->second<<endl;
		itr++;
	}
	end = clock();
	cout<<"STL MAP输出到文件花费时间为:"<<end-start<<"毫秒"<<endl;
	out.close();

	start = clock();
	int sum1=0,sum2=0;
	ifstream searchIn("search.dat");
	while(searchIn>>word)
	{
		if(dict[word] != 0)
		{
			sum1++;
		}
		else
		{
			sum2++;
		}
	}
	end = clock();
	cout<<"找到单词:"<<sum1<<"-->"<<"没有找到单词:"<<sum2<<endl;
	cout<<"查询花费时间:"<<end-start<<endl;
	return 0;
}

字典树实现代码:

#include<iostream>
#include<string.h>
#include<fstream>
#include<ctime>

using namespace std;
char str[20];//用于在输出字典树中的单词时使用。
struct Node
{
	int cnt;
	struct Node *child[26];
	Node()
	{
		int i;
		for(i=0; i<26; i++)
		{
			child[i] = NULL;
		}
		cnt = 0;
	}
};

/*
*
* 将一个字符串插入到字典树中
*
*/
void Insert(Node *root, char word[])
{
	Node *p = root;
	int i,index;
	int len = strlen(word);

	for(i=0; i<len; i++)
	{
		index = word[i] - 'a';//这里是一个hash算法,只考虑小写字母的情况
		if(p->child[index] == NULL)
		{
			p->child[index] = new Node();
		}
		p = p->child[index];
	}
	p->cnt++;//单词数加1。
}

/*
*
* 字符串输出到文件
*/
void OutToFile(char *word,int cnt)
{
	ofstream out("out.txt",ios::app);
	out<<word<<" "<<cnt<<endl;
	out.close();
}
/*
*将字典树中的单词及其出现次数输出
*
*/
void OutputWord(Node *p,int length)
{
	int i;
	if(p->cnt != 0)//找到了一个字符串
	{
		str[length] = '\0';
		OutToFile(str,p->cnt);
	}
	for(i=0; i<26; i++)
	{
		if(p->child[i] != NULL)
		{
			str[length] = i+'a';//根据下标还原字符
			OutputWord(p->child[i],length+1);
		}
	}
}

/**
* 查询word是否在字典树中
*
*/
int SearchWord(Node *p,char word[])
{
	int i,index;
	int len = strlen(word);
	for(i=0; i<len; i++)
	{
		index = word[i]-'a';
		if(p->child[index] == NULL)//没有找到
		{
			return 0;
		}
		p = p->child[index];
	}
	if(p->cnt > 0)
	{
		return 1;//找到
	}
	else//前缀字符串不能算是有这个单词
	{
		return 0;
	}
}

/*
*
*销毁字典树
*
*/
void DestroyTrieTree(Node *p)
{
	int i;
	for(i=0; i<26; i++)
	{
		if(p->child[i] != NULL)
		{
			DestroyTrieTree(p->child[i]);
		}
	}
	delete p;
}

int main()
{
	Node *Root = new Node();
	char word[20];
	clock_t start,end;
	start = clock();
	ifstream in("data.dat");
	while(in>>word)
	{
		Insert(Root,word);
	}
	end = clock();
	cout<<"使用字典树进行统计花费时间:"<<end-start<<"毫秒"<<endl;
	start = clock();
	OutputWord(Root,0);
	end = clock();
	cout<<"输出到文件花费时间:"<<end-start<<"毫秒"<<endl;
	in.close();
	int sum1=0,sum2=0;
	start = clock();
	ifstream searchIn("search.dat");
	while(searchIn>>word)//
	{
		if(SearchWord(Root,word) )
		{
			sum1++;
		}
		else
		{
			sum2++;
		}
	}
	searchIn.close();
	end = clock();
	cout<<"找到单词:"<<sum1<<"-->"<<"没有找到单词:"<<sum2<<endl;
	cout<<"查询花费时间:"<<end-start<<endl;

	/** 销毁字典树 */
	for(int i=0; i<26; i++)
	{
		if(Root->child[i] != NULL)
		{
			DestroyTrieTree(Root->child[i]);//销毁字典树
		}
	}
	return 0;
}

下面是两个程序在release版本下的运行情况:

一、运行时间方面:从上面可以看出在统计和查询过程中使用字典树的速度明显优于map。假设字符串长度为n,共有m个关键字。由于map其底层是由红黑树(红黑树本质一种排序二叉树)支持,所以将一个字符串插入到map中需要log(m)次才能找到其所在位置。在这log(m)次中每次极端情况下需要进行n次比较。所以往map中插入一个字符串需要O(n*log(m))的时间复杂度。对于字典树从上面的程序中可以看出。插入一个字符串只与字符串的长度有关而与关键字的个数无关,其时间复杂度为O(n)。而在将所有的关键字及其出现次数写到外部文件时,字典树花费了巨大的时间。这是由于字典树的遍历是递归的,大量的时间花在了栈的建立和销毁上。

二、在内存空间使用方面

以插入一个字符串a为例,插入到字典树中正真存储有用的数据只占一个空间,另外需要26个空间的指针域。而插入到map,其底层是红黑树,数据占用一个空间;另外再需两个空间的指针指向其左右孩子。所以在空间使用方面,map使用较少的内存空间。

三、适用场合

(1)字典树及map的比较:1.字典树在插入和查询一个的字符串的的时间较map快。2.map比字典树使用更少的内存空间。3.在需要在统计的数据写到外部文件时,map比字典树快很多。

(2)字典树的适用场合:

在不需要将字典树的数据写到外部文件的情况,并对内存空间没有太多要求以及对系统响应要求较高的系统中使用字典树优于map。比如在12306网站的订票页面,在出发地框中输入bj就会提示“北京”等信息。

在对系统响应要求不高而对内存有限制的系统,以及需要将内存中存储的数据写到外部文件的系统使用map优于字典树。

STL MAP及字典树在关键字统计中的性能分析的更多相关文章

  1. POJ 2503 Babelfish(map,字典树,快排+二分,hash)

    题意:先构造一个词典,然后输入外文单词,输出相应的英语单词. 这道题有4种方法可以做: 1.map 2.字典树 3.快排+二分 4.hash表 参考博客:[解题报告]POJ_2503 字典树,MAP ...

  2. 51nod 1095 Anigram单词【hash/map/排序/字典树】

    1095 Anigram单词 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 一个单词a如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b ...

  3. (字典树模板)统计难题--hdu--1251

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1251 在自己敲了一遍后终于懂了,这不就用了链表的知识来建立了树,对!就是这样的,然后再查找 代码: #i ...

  4. 字典树 HDU 1251 统计难题

    ;} 之前写的#include<iostream> #include<algorithm> #include<stdio.h> using namespace st ...

  5. poj 1204 Word Puzzles(字典树)

    题目链接:http://poj.org/problem?id=1204 思路分析:由于题目数据较弱,使用暴力搜索:对于所有查找的单词建立一棵字典树,在图中的每个坐标,往8个方向搜索查找即可: 需要注意 ...

  6. 算法学习笔记(一)C++排序函数、映射技巧与字典树

    1.头文件algorithm中有函数sort()用于排序,参数为:排序起始地址,排序结束地址,排序规则(返回bool型)例如,要将array[] = {5,7,1,2,9}升序排列,则使用: bool ...

  7. poj2513--并查集+欧拉路+字典树

    经典好题,自己不知道哪里错了交上去是RE,可能是数组开的不好吧,字典树老碰到这种问题.. 先马上别人的代码,有空对拍看看 #include <cstdio> #include <cs ...

  8. hdu2609 How many 字典树+最小表示法

    Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100,tell meHow many ...

  9. HDOJ/HDU 1251 统计难题(字典树啥的~Map水过)

    Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己 ...

随机推荐

  1. openSuSE DNS SERVER CONFIG

    system:openSuSE 12.3(much better and frendly than the 12.1 in network config)1,network config,attent ...

  2. 实现 DIV 固定定位在网页主体部分最右侧

    position:fixed 相对于窗口的固定定位,这个窗口可理解为可视窗口,除了浏览器自己的东西,剩下的就是这个可视窗口.而大部分的网页都是窄屏设计,比如说网页主体部分固定宽 1200px,或者自适 ...

  3. log4j使用

    Spring中在src/main/resources下创建log4j.xml 或log4j.properties,在maven下打包时resources文件夹下面的文件会自动copy到WEB-INF/ ...

  4. Effective C++ 5.实现

    //条款26:尽量延后变量的定义式出现的时间 // 1.不仅应该延后变量的定义,更应该直到使用该变量的前一刻为止,甚至应该尝试延后这份定义直到能够给它初始值为止.如果这样,不仅能够避免构造和析构的非必 ...

  5. sdutoj 2154 Shopping

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2154 Shopping Time Limit: ...

  6. jquery ajax 个人总结

    jquery : 在获取对象的时候,不要用dem的与jquery的混合写法,有的时候 用js获取到的对象 没有JQUERY对应的方法  会报一些不知道的错误.(即如果要使用jquery 就使用jque ...

  7. oracle 分区表的维护

    1:添加分区: ALTER TABLE SALES ADD PARTITION P3 VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD')); SAL ...

  8. Javascript动态加载Html元素到页面Dom文档结构时执行顺序的不同

    我们有时会通过ajax动态获取一段Html代码,并且将这段代码通过javascript放到页面的Dom结构中去. 而很多时候通过ajax动态获取的Html代码中也包含javascript代码,有一点需 ...

  9. 用javascript在客户端删除某一个cookie键值对

    下面这个方法展示如何在客户端浏览器上用javascript删除某一个cookie键值对. //用javascript删除某一个cookie的方法,该方法传入要删除cookie的名称 function ...

  10. 最长上升子序列O(nlogn)算法详解

    最长上升子序列 时间限制: 10 Sec   内存限制:128 MB 题目描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.我们想知道此时最长上升子 ...