有很久没有写了。。。。果然没有坚持。。。
昨天和今天在搞字典树……
这个版本的字典树用到了各种指针链表……刚刚学习到正好加深了印象……
首先先贴一下标程代码
//============================================================================
// Name : Trie Tree Standard source
// Author : zzjzxh
// Version :
// Copyright : Your copyright notice
// Description : Trie Tree
// Time : 2016-11-30 21:08:20
//============================================================================
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define MAX 26 //MAX是最大的指针数量,如果只有小写字母就是26,大小写字母52,数字10.视情况而定
struct Trie //字典树结构体
{
int v; //需要的东西,也需要视情况而定。不过在这里一般都是当前元素在数据中作为前缀的个数
struct Trie *next[MAX];
};
struct Trie *root; //根节点,不代表任何元素。
/*---------------------建立or插入--------------------*/
struct Trie *newNode() //建开辟新空间
{
int j;
struct Trie *q=(struct Trie *)malloc(sizeof(struct Trie));
for (j=0;j<MAX;j++) q->next[j]=NULL; //不可或缺!
q->v=1; //因为刚刚建立这个节点,所以默认的目前前缀里有当前元素的只有一个
return q; //返回q的地址
}
void creatTrie(char *str) //建立or插入,都在这里
{
int len=strlen(str);
int i,j,id,a;
struct Trie *p=root;
for (i=0;i<len;i++)
{
id=str[i]-'a';
if (p->next[id]==NULL) //如果要找的这个元素还没建立
{ //建立
p->next[id]=newNode();
p=p->next[id]; //p要永远保持指向最后一个节点
}
else
{ //已经存在了
p=p->next[id];
p->v++; //说明又多了一个前缀里包含这个元素的数据,v就+1
}
}
}
/*------------------------------------------------------*/
/*---------------------建立or插入-----------------------*/
int insert(char *str) //这个函数和上面两个函数等价(newNode+creatTrie),都是插入 (新建就相当于在0的基础上插入)
{
int i,j,len,id;
struct Trie *p=root,*q=NULL;
len=strlen(str);
for (i=0;i<len;i++)
{
id=str[i]-'0';
if (p->next[id]==NULL)
{
q=(struct Trie *)malloc(sizeof(struct Trie));
for (j=0;j<MAX;j++) q->next[j]=NULL;
q->v=1;
p->next[id]=q;
p=p->next[id];
}
else
{
p=p->next[id];
p->v++;
}
}
p->v=-1; //在这里可以把每个数据的最后一个元素标记一下(如果需要的话)
return 0;
}
/*------------------------------------------------------*/
/*---------------------查找-----------------------*/
int search(char *str) //寻找函数
{
int i,id,len;
struct Trie *p=root;
len=strlen(str);
for (i=0;i<len;i++)
{
id=str[i]-'a';
if (p->next[id]==NULL) return 0; //如果没有就返回空
p=p->next[id]; //有p就移动一下
}
return (p->v); // 返回的是有多少个数据以该元素(及其祖先们)为前缀
}
/*------------------------------------------------*/
/*---------------------释放内存!-----------------------*/ //一般多组数据的时候需要释放内存。请仔细考虑释放内存的位置!请仔细考虑释放的东西!是否需要重建root!
int release(struct Trie *T)
{
int i;
if (T==NULL) return 0;
for (i=0;i<MAX;i++)
{
if (T->next[i]!=NULL)
release(T->next[i]);
}
free(T);
return 0;
}
/*-----------------------------------------------------*/
int main() //主函数
{
char s[101];
root=(struct Trie *)malloc(sizeof(struct Trie)); //这个是为root分配空间
int i;
for (i=0;i<MAX;i++) root->next[i]=NULL; //莫忘!
while (gets(s) && strlen(s)) //因为是题目截出来的这里根据题目条件而定
{
creatTrie(s); //建立,或者写为insert(s)
}
while (gets(s)) //因为是题目截出来的这里根据题目条件而定
{
printf("%d\n",search(s)); //找啊找……
}
release(root); //释放在这里
return 0;
}
感觉写的还是很详细了。。。
有个东西需要表述一下……
结构体中v的含义需要好好理解,在这里是以 现在这个元素到根元素之间 为前缀的 数据的个数。
来个图便于理解
接触了两种题目
1.hdu1251 查找相同前缀的数据个数
直接上代码吧。。。不需要太多解释
//============================================================================
// Name : HDU1251.c
// Author : zzjzxh
// Version :
// Copyright : Your copyright notice
// Description : Trie Tree
// Time : 2016-11-30 20:39:03
//============================================================================
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define MAX 26
struct Trie
{
int v;
struct Trie *next[MAX];
};
struct Trie *root;
struct Trie *newNode()
{
int j;
struct Trie *q=(struct Trie *)malloc(sizeof(struct Trie));
for (j=0;j<MAX;j++) q->next[j]=NULL;
q->v=1;
return q;
}
void creatTrie(char *str)
{
int len=strlen(str);
int i,j,id,a;
struct Trie *p=root;
for (i=0;i<len;i++)
{
id=str[i]-'a';
if (p->next[id]==NULL)
{
p->next[id]=newNode();
p=p->next[id];
}
else
{
p=p->next[id];
p->v++;
}
}
}
int search(char *str)
{
int i,id,len;
struct Trie *p=root;
len=strlen(str);
for (i=0;i<len;i++)
{
id=str[i]-'a';
if (p->next[id]==NULL) return 0;
p=p->next[id];
}
return (p->v);
}
int main()
{
char s[101];
root=(struct Trie *)malloc(sizeof(struct Trie));
int i;
for (i=0;i<MAX;i++) root->next[i]=NULL;
memset(s,0,sizeof(s));
while (gets(s) && strlen(s))
{
creatTrie(s);
}
memset(s,0,sizeof(s));
while (gets(s))
{
printf("%d\n",search(s));
}
return 0;
}
2.hdu1671 第二种题,查询前缀存在不存在……
//============================================================================
// Name : HDU1671.c
// Author : zzjzxh
// Version :
// Copyright : Your copyright notice
// Description : Trie Tree
// Time : 2016-11-30 20:39:03
//============================================================================
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define MAX 10
struct Trie
{
int v;
struct Trie *next[MAX];
};
struct Trie *root;
int insert(char *str)
{
int i,j,len,id;
struct Trie *p=root,*q=NULL;
len=strlen(str);
for (i=0;i<len;i++)
{
id=str[i]-'0';
if (p->next[id]==NULL)
{
q=(struct Trie *)malloc(sizeof(struct Trie));
for (j=0;j<MAX;j++) q->next[j]=NULL;
q->v=1;
p->next[id]=q;
p=p->next[id];
}
else
{
if ((p->next[id]->v==-1)||((i==len-1)&&(p->next[id]->v>0)))
return -1;
p=p->next[id];
p->v++;
}
}
p->v=-1;
return 0;
}
int release(struct Trie *T)
{
int i;
if (T==NULL) return 0;
for (i=0;i<MAX;i++)
{
if (T->next[i]!=NULL)
release(T->next[i]);
}
free(T);
return 0;
}
int main()
{
// FILE *fp1,*fp2;
// fp1=fopen("hdu1671.in","r");
// fp2=fopen("hdu1671.out","w");
int i,t,n,flag;
char str[20];
// fscanf(fp1,"%d",&t);
scanf("%d",&t);
while (t-->0)
{
// fscanf(fp1,"%d",&n);
scanf("%d",&n);
flag=0;
root=(struct Trie *)malloc(sizeof(struct Trie));
for (i=0;i<MAX;i++) root->next[i]=NULL;
for (i=0;i<n;i++)
{
// fscanf(fp1,"%s",str);
scanf("%s",str);
if (flag) continue;
if (insert(str)==-1)
{
// fprintf(fp2,"NO\n");
flag=1;
}
}
// if (!flag) fprintf(fp2,"YES\n");
// else fprintf(fp2,"NO\n");
if (!flag) printf("YES\n");
else printf("NO\n");
release(root);
}
// fclose(fp1);
// fclose(fp2);
return 0;
}
写这里的时候也顺便学习了一下文件输入输出……写注释的都是文件输入输出……
int main()
{
FILE *fp1,*fp2;
fp1=fopen("file.in","r");
fp2=fopen("file.out","w");
/*programe body PS:scanf(,)->fscanf(fp1,) printf(,)->fprintf(fp2,);*/
fclose(fp1);
fclose(fp2);
return 0;
}
嗯嗯……就这样……