转载请注明出处: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 1204 Word Puzzles(字典树)

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

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

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

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

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

  4. hdu_1251统计难题(字典树Trie)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...

  5. hdu 1251 统计难题 (字典树入门题)

    /******************************************************* 题目: 统计难题 (hdu 1251) 链接: http://acm.hdu.edu. ...

  6. hdu 1251:统计难题(字典树,经典题)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...

  7. ACM:统计难题 解题报告-字典树(Trie树)

    统计难题 Time Limit:2000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status ...

  8. hdu1251 字典树or map

    一道字典树的题,不过看起来用map更为简单 传送门 题意: 给出一堆字符串构成一个字典,求字典里以某字符串为前缀的字符串有几个 思路: 输入字符串时把字符串的前缀全部存进map并标记次数 查询时直接输 ...

  9. poj 2503 Babelfish(Map、Hash、字典树)

    题目链接:http://poj.org/bbs?problem_id=2503 思路分析: 题目数据数据量为10^5, 为查找问题,使用Hash或Map等查找树可以解决,也可以使用字典树查找. 代码( ...

随机推荐

  1. SOAPUI使用教程-测试JDBC数据库

    soapUI中有除了开源版本的一些非常实用的功能: 使用在项目级配置的JDBC连接 使用向导创建复杂的查询. 结果显示XML输出视图(以及该使用向导在此视图中提供的XPath断言). 提供JDBC连接 ...

  2. hibernate笔记--单向多对一映射方法

    假设我们要建两张表,学生信息表(student)和年级信息表(grade),关系是这样的: 我们可以看出学生表和=年级表是多对一的关系,多个学生会隶属于一个班级,这种关系在hibernate中成为单边 ...

  3. 侣行APP

    本次要做的是团队共同完成一个项目.由队长组织,全体队员一起讨论分析并完成一款APP的需求调研,分析等工作. 1.团队介绍 队长:杨晓帅 队员                               ...

  4. Sprint

    Sprint冲刺 1.选题 <寿司点餐系统> 2.app名 <Sushi> 3.团名 ZEG 4.目标 制作一个成型的人性化的寿司点餐系统,介绍各种寿司的材料做法吃法以及价格, ...

  5. C语言简易文法(无左递归)

    <程序> -〉 <外部声明> | <函数定义><外部声明> -〉<头文件> | <变量> | <结构体> <头 ...

  6. 解决&quot;415 Cannot process the message because the content type &#39;application/x-www-form-urlencoded&#39; was not the expected type &#39;text/xml; charset=utf-8&#39;&quot;

    wcf basicHttpBinding content-type    text/xml;charset=utf-8 wsHttpBinding  'application/soap+xml; ch ...

  7. python的json模块

    Python JSON 本章节我们将为大家介绍如何使用 Python 语言来编码和解码 JSON 对象. 环境配置 在使用 Python 编码或解码 JSON 数据前,我们需要先安装 JSON 模块. ...

  8. Python Web实战 - 基于Flask实现的黄金点游戏

    一.简介 团队成员: 领航者:张旭 驾驶员:张国庆 项目简介: 项目名称:基于B/S模式的黄金点游戏 采用技术: 后端:Python + Sqlite3 前端:HTML + CSS + JS + Bo ...

  9. 从协议VersionedProtocol开始3&mdash;&mdash;ClientProtocol、DatanodeProtocol、NamenodeProtocol、RefreshAuthorizationPolicyProtocol、RefreshUserMappingsProtocol

    1.ClientProtocol这个玩意的版本号是61L:DatanodeProtocol 是26L:NamenodeProtocol是 3L;RefreshAuthorizationPolicyPr ...

  10. jQuery Mobile方向感应事件

    在现在的智能手机中,都有对方向变换的自动感知功能,比如当手机方向从水平方向切换到垂直方向时,则会触发该事件.在jQuery Mobile中,可以通过orientationchange事件进行绑定,并且 ...