字典树,又称为单词查找树,Trie树。是一种用于快速检索多叉树的结构。典型应用于统计,排序和保存大量字符串。利用字符串的前缀来减少存储空间,减少无谓的比较,提高查询效率。
字典树根节点不包含任何数据,其余节点仅包含一个字母,并且每个节点包含的字母各不相同。
字典树的查找检索总是始于根节点,先取得对应的首字母,然后根据对应的子树进行继续检索查找,往往给字典树一个结束信息标志,作为所有字符成功读出的结束标志。
下面是一个电话号码格式数字转化的问题。(POJ 1002 487-3279)
Description
企业喜欢用容易被记住的电话号码。让电话号码容易被记住的一个办法是将它写成一个容易记住的单词或者短语。例如,你需要给滑铁卢大学打电话时,可以拨打TUT-GLOP。有时,只将电话号码中部分数字拼写成单词。当你晚上回到酒店,可以通过拨打310-GINO来向Gino's订一份pizza。让电话号码容易被记住的另一个办法是以一种好记的方式对号码的数字进行分组。通过拨打必胜客的“三个十”号码3-10-10-10,你可以从他们那里订pizza。
电话号码的标准格式是七位十进制数,并在第三、第四位数字之间有一个连接符。电话拨号盘提供了从字母到数字的映射,映射关系如下:
A, B, 和C 映射到 2
D, E, 和F 映射到 3
G, H, 和I 映射到 4
J, K, 和L 映射到 5
M, N, 和O 映射到 6
P, R, 和S 映射到 7
T, U, 和V 映射到 8
W, X, 和Y 映射到 9
Q和Z没有映射到任何数字,连字符不需要拨号,可以任意添加和删除。 TUT-GLOP的标准格式是888-4567,310-GINO的标准格式是310-4466,3-10-10-10的标准格式是310-1010。
如果两个号码有相同的标准格式,那么他们就是等同的(相同的拨号)
你的公司正在为本地的公司编写一个电话号码薄。作为质量控制的一部分,你想要检查是否有两个和多个公司拥有相同的电话号码。
电话号码的标准格式是七位十进制数,并在第三、第四位数字之间有一个连接符。电话拨号盘提供了从字母到数字的映射,映射关系如下:
A, B, 和C 映射到 2
D, E, 和F 映射到 3
G, H, 和I 映射到 4
J, K, 和L 映射到 5
M, N, 和O 映射到 6
P, R, 和S 映射到 7
T, U, 和V 映射到 8
W, X, 和Y 映射到 9
Q和Z没有映射到任何数字,连字符不需要拨号,可以任意添加和删除。 TUT-GLOP的标准格式是888-4567,310-GINO的标准格式是310-4466,3-10-10-10的标准格式是310-1010。
如果两个号码有相同的标准格式,那么他们就是等同的(相同的拨号)
你的公司正在为本地的公司编写一个电话号码薄。作为质量控制的一部分,你想要检查是否有两个和多个公司拥有相同的电话号码。
Input
输入的格式是,第一行是一个正整数,指定电话号码薄中号码的数量(最多100000)。余下的每行是一个电话号码。每个电话号码由数字,大写字母(除了Q和Z)以及连接符组成。每个电话号码中只会刚好有7个数字或者字母。
Output
对于每个出现重复的号码产生一行输出,输出是号码的标准格式紧跟一个空格然后是它的重复次数。如果存在多个重复的号码,则按照号码的字典升序输出。如果输入数据中没有重复的号码,输出一行:
No duplicates.
No duplicates.
Sample Input
12
4873279
ITS-EASY
888-4567
3-10-10-10
888-GLOP
TUT-GLOP
967-11-11
310-GINO
F101010
888-1200
-4-8-7-3-2-7-9-
487-3279
Sample Output
310-1010 2
487-3279 4
888-4567 3
12
4873279
ITS-EASY
888-4567
3-10-10-10
888-GLOP
TUT-GLOP
967-11-11
310-GINO
F101010
888-1200
-4-8-7-3-2-7-9-
487-3279
Sample Output
310-1010 2
487-3279 4
888-4567 3
#include<iostream>
using namespace std;
typedef struct trietree *Ptree;
struct trietree //字典树
{
bool arrive; //单词结束标志
int treenum; //单词的个数
Ptree next[10]; //字典树的儿子
}node[1000000];
int size; //字典树的规模
bool findsolve; //是否找到重复串的标记
int dispose(char *p); //将字符串转化为整形数字
void addnum(int num); //增加数字串
void newtree(int no); //建新树
void dfs(char phone[9],int m,Ptree p); //深度搜索遍历字典树
/*将字符串转化为整形数字 */
int dispose(char *p)
{
int num = 0;
char *q = p;
while(*++p != '\0');
p--; //将字符串指针移向末尾
while(p >= q) //从后向前遍历字符串指针
{
if(*p == '-') //忽略“-”
{
p--;
continue;
}
num *= 10; //计算字符串对应的数字
if(*p >= 'A' && *p <= 'Y')
num += (*p - 'A' - (*p > 'Q'))/3 + 2; //将字符转化为数字
else if(*p >= '0' && *p <= '9')
num += *p - '0';
p--;
}
return num;
}
/* 增加数字串 */
void addnum(int num)
{
Ptree p = &node[1];
int i,k;
for (i=0;i<=6;i++) //将7个数字插入
{
k = num % 10;
num /= 10;
if (! p -> next[k]) //插入位置不存在,创建该节点
{
newtree(++size);
p->next[k] = &node[size];
}
p = p->next[k];
}
p->arrive = true; //到达单词末尾
p->treenum++;
return;
}
/* 建新树 */
void newtree(int no)
{
int i;
node[no].arrive = false;
node[no].treenum = 0;
for (i=0;i<=9;i++)
{
node[no].next[i] = NULL;
}
return;
}
/* 深度搜索遍历字典树 */
void dfs(char phone[9], int m, Ptree p)
{
if (true == p->arrive) //如果节点存在数字
{
if (p->treenum > 1)
{
for (int i=1;i<=7;i++)
{
if (i == 4)
{
cout<<"-";
}
cout<<phone[i];
}
cout<<" "<<p->treenum<<endl;
findsolve = true;
}
return;
}
for (int i=0;i<=9;i++)
{
if (p->next[i])
{
phone[m+1] = i + '0';
dfs(phone,m+1,p->next[i]);
}
}
return;
}
int main()
{
int n; //串的个数
int i,j;
int number; //字符串转化得到数字
char phone[9];
char ch[80]; //字符串
cin>>n;
findsolve = false;
size = 1;
newtree(1);
for (i=1;i<=n;i++)
{
cin>>ch;
number = dispose(ch);
addnum(number);
}
dfs(phone,0,&node[1]);
if (!findsolve)
{
cout<<"No duplicates."<<endl;
}
system("pause");
return 0;
}
本文介绍了字典树(Trie树)的数据结构及其在解决电话号码转化问题(POJ 1002 487-3279)中的应用。字典树通过利用字符串前缀优化存储和查询效率,每个节点存储一个字母,并以特定的结束信息标志表示完整字符串。

2766

被折叠的 条评论
为什么被折叠?



