BUAA(2021春) 词频统计(BST)+二叉排序树的两种构造形式及快慢分析

48 篇文章 152 订阅

看前须知

要点介绍和简要声明.

第五次上机题汇总

树叶节点遍历(树-基础题).

词频统计(BST)+二叉排序树的两种构造形式及快慢分析.

计算器(表达式树实现)(只要打出优先级表==有手就行).

网络打印机选择——伪树状数组(这题杀我)(ಥ_ಥ).

实验:树的构造与遍历——根据提示循序渐进(可惜提示有问题Ծ‸Ծ).

题目内容

问题描述

编写程序统计一个英文文本文件中每个单词的出现次数(词频统计),并将统计结果按单词字典序输出到屏幕上。

要求:程序应用二叉排序树(BST)来存储和统计读入的单词。

注:在此单词为仅由字母组成的字符序列。包含大写字母的单词应将大写字母转换为小写字母后统计。在生成二叉排序树不做平衡处理。

输入形式

打开当前目录下文件article.txt,从中读取英文单词进行词频统计。

输出形式

程序应首先输出二叉排序树中根节点、根节点的右节点及根节点的右节点的右节点上的单词(即root、root->right、root->right->right节点上的单词),单词中间有一个空格分隔,最后一个单词后没有空格,直接为回车(若单词个数不足三个,则按实际数目输出)。

程序将单词统计结果按单词字典序输出到屏幕上,每行输出一个单词及其出现次数,单词和其出现次数间由一个空格分隔,出现次数后无空格,直接为回车。

样例

当前目录下文件article.txt内容如下:

“Do not take to heart every thing you hear.”

“Do not spend all that you have.”

“Do not sleep as long as you want;”

输出

do not take
all 1
as 2
do 3
every 1
have 1
hear 1
heart 1
long 1
not 3
sleep 1
spend 1
take 1
that 1
thing 1
to 1
want 1
you 3

样例说明

程序首先在屏幕上输出程序中二叉排序树上根节点、根节点的右子节点及根节点的右子节点的右子节点上的单词,分别为do not take,然后按单词字典序依次输出单词及其出现次数。

题解

易错点和难点

易错点倒是没有,难点主要在于怎么构建BST,对于BST其实使用两种构建的形式,一种是通过传递struct TreeNode* 来构建,另一种是通过传递== struct TreeNode** ==来构建,对于两种构建形式,必然就会有谁快谁慢的问题,自己可以先尝试一下,比较比较。我在最后会告诉大家两者的具体构造形式和快慢比较。

参考代码

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#include<stdbool.h>
typedef struct TreeNode {  //树的结构体 
    char val[200];
    int times;
    struct TreeNode *left;
    struct TreeNode *right;
}Tree,*Treep;

void VISIT(Treep t);       //访问树节点的内容 
void inorder(Treep t);     //中序遍历 
void insertBST(Treep *t,char *num); //构造二叉排序树BST(这个方法是传递struct TreeNode**) 

void GetArticle(FILE *fp1);  //读取文章 
void GetWord();     //获取单词 

char s[2000000],tmp[200],ch;
int i,j,k;
Treep root=NULL;


int main()
{	
	FILE *fp1 = fopen("article.txt","r");
	GetArticle(fp1);
	GetWord();
	if((root!=NULL) && (root->right!=NULL) && (root->right->right!=NULL))  //按照题目要求输出BST的内容 
		printf("%s %s %s\n",root->val,root->right->val,root->right->right->val);
	else if((root!=NULL) && (root->right!=NULL))
		printf("%s %s\n",root->val,root->right->val);
	else if (root!=NULL)
		printf("%s\n",root->val);
	inorder(root);
	return 0;
}
void VISIT(Treep t)
{
	printf("%s %d\n",t->val,t->times); //访问单词和次数 
}
void inorder(Treep t)  //中序遍历 
{
    if(t!=NULL){
        inorder(t->left);
        VISIT(t);
        inorder(t->right);
    }
}
void insertBST(Treep *t,char *num)//构造BST 
{
	if(*t==NULL)//如果节点为空,构造节点 
	{
		*t=(Treep)malloc(sizeof(Tree));
		strcpy((*t)->val,num);
		(*t)->times=1;
		(*t)->left=NULL;
		(*t)->right=NULL;
	}
	else if(strcmp((*t)->val,num)>0)//字典序排序 
	{
		insertBST(&((*t)->left),num);
	}	
	else if(strcmp((*t)->val,num)<0)	//字典序排序 
	{
		insertBST(&((*t)->right),num);
	}
	else if(strcmp((*t)->val,num)==0)//相同则次数增加 
	{
		(*t)->times++;
	}
}
void GetArticle(FILE *fp1)  //读文章 
{
	ch=fgetc(fp1);
	i=0;
	while(ch!=EOF)
	{
		if(isalpha(ch)) s[i]=tolower(ch);
		else s[i]=ch;
		i++;
		ch=fgetc(fp1);
	}
}
void GetWord()  //获取单词 
{
	for(i=0;i<strlen(s);i++)
	{
		if(isalpha(s[i]))  //找到单词开头 
		{
			for(j=i;j<strlen(s);j++)
			{
				if(!isalpha(s[j]))  //找到单词结尾 
				{
					break;
				}
			}
			memset(tmp,'\0',sizeof(tmp));
			for(k=0;k<j-i;k++)
			{
				tmp[k]=s[i+k]; //tmp存储的是单词; 
			}
			insertBST(&root,tmp); //通过根节点构造BST 
			i=j;
		}
		else	continue;
	}
}

补充测试的数据

没有特别注意的地方,只要构造BST成功了,那么想不AC都难。

BST的两种构造形式及快慢分析

BST有两种构造形式

  1. 一种是传递struct TreeNode* (Treep)
Treep insertBST(Treep t,char *num)  //构造BST 
{
	if(t==NULL) 
	{
		t=(Treep)malloc(sizeof(Tree));
		strcpy(t->val,num);
		t->times=1;
		t->left=NULL;
		t->right=NULL;
	}
	else if(strcmp(t->val,num)>0) 
	{
		t->left=insertBST(t->left,num);
	}	
	else if(strcmp(t->val,num)<0)	
	{
		t->right=insertBST(t->right,num);
	}
	else if(strcmp(t->val,num)==0)	
	{
		t->times++;
	}
}
  1. 一种是传递struct TreeNode** (Treep*)
void insertBST(Treep *t,char *num)
{
	if(*t==NULL)
	{
		*t=(Treep)malloc(sizeof(Tree));
		strcpy((*t)->val,num);
		(*t)->times=1;
		(*t)->left=NULL;
		(*t)->right=NULL;
	}
	else if(strcmp((*t)->val,num)>0)
	{
		insertBST(&((*t)->left),num);
	}	
	else if(strcmp((*t)->val,num)<0)
	{
		insertBST(&((*t)->right),num);
	}
	else if(strcmp((*t)->val,num)==0)
	{
		(*t)->times++;
	}
}

对于两种构造形式,自己实操也不难发现,后者其实是更快的,因为在一般情况下,直接对地址进行操作是最快的。如果大家对此还没有什么概念,觉得两者都差不多,觉得记得麻烦只想记住一种,笔者建议记住后者,因为无论以后是大数据操作还是OJ卡运行时间,前者(传递Treep)会经常达不到要求,如果对此还是没有什么感觉可以移步题单链接,前者会让你体验到TLE的痛苦。。。。

题单链接

看看前者被TLE的题目对于时间的要求是多么严格(6ms噗)

传递Treep就让你超时哈哈哈哈.

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值