浙江大学陈越教授数据结构PTA 题目——7-1 词频统计

???? 

#include <stdio.h>
#include <malloc.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>

#define KEYLENGTH 15//长度超过15的单词将只截取保留前15个单词字符 
#define MAXTABLESIZE 111111//允许开辟的最大散列表长度 
#define MAXWORDLEN 80 //单词输入的最大长度 
typedef char ElementType[KEYLENGTH+1];//链表的数据域是一个字符串 
typedef int Index;//散列地址类型 

typedef struct LNode *PtrToLNode;//单链表一个结点的定义 
struct LNode{
	ElementType Data;//结点的数据域是一个字符串 
	int Count;//存储该单词的出现次数,空头结点的Count用来存储该单链表的结点数 
	PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;

typedef struct TblNode *HashTable;
struct TblNode{//散列表结点的定义 
	int TableSize;
	List Heads;
};

int NextPrime(int n)//返回大于n且不超过MAXTABLESIZE的最小素数 
{
	int i,p;
	for(p=n+1;p<MAXTABLESIZE;p++){
		for(i=2; i<=p; i++){
			if(p%i== 0)	break;
		}
		if(i>=p) return p;
	} 
}

HashTable CreateTable(int TableSize)
{
	HashTable H;
	int i;
	H = (HashTable)malloc(sizeof(struct TblNode));
	H->TableSize =NextPrime(TableSize);//保证散列表最大长度是素数
	H->Heads =(List)malloc(H->TableSize *sizeof(struct LNode));
	for(i=0; i<H->TableSize ;i++){//初始链表头结点 
		H->Heads[i].Data[0] = '\0';
		H->Heads[i].Next =NULL;
	} 
	return H;
}

bool IsWordChar(char c)//判断一个字符是否为合法字符 
{
	if(c>='a'&&c<='z' || c>='A'&&c<='Z' || c>='0'&&c<='9' ||c=='_') return true;
	else return false;
}

int zongchang[111]={0};//记录每个单词的开始到下一个单词开始的总长度 
int GetAWord(char *shuru,ElementType word,int j,int k)
{
	char tempword[MAXWORDLEN+1], c;
	int i,len=0;
	for(i=j;shuru[i];i++){
		c=shuru[i];
		if(len==0 && !IsWordChar(c)) zongchang[k]++; 
		if(IsWordChar(c)) {
			tempword[len++] =c;
			zongchang[k]++;
		}
		if(len && !IsWordChar(c)) {
			zongchang[k]++;
			break;//一个单词结束 
		}
	}
	tempword[len] = '\0';//设定字符串结束符
	if(len>KEYLENGTH){//长度超过15的单词将只截取保留前15个单词字符
		tempword[KEYLENGTH] = '\0';
		len = KEYLENGTH;
	} 
	strcpy(word,tempword);
	return len; 
}

int Hash(const char *Key, int TableSize)//确定关键词所在的散列函数的地址 
{
	int H=0;
	while(*Key!='\0') H=(H<<5)+ *Key++;
	return H%TableSize;
} 

Position Find(HashTable H, ElementType Key)
{
	Position P;
	Index Pos;
	Pos = Hash(Key, H->TableSize );//初始散列地址 
	P =H->Heads[Pos].Next ;
	while(P && strcmp(P->Data ,Key)) P=P->Next ;
	return P; 
}

void InsertAndCount(HashTable H, ElementType Key)
{
	Position P,NewCell;
	Index Pos;
	
	P = Find(H,Key);
	if(!P ){//关键词未找到,可以插入 
		NewCell = (Position)malloc(sizeof(struct LNode));
		strcpy(NewCell->Data ,Key);
		NewCell->Count =1;//新单词第一次出现 
		Pos =Hash(Key, H->TableSize );//初始散列地址
		NewCell->Next =H->Heads[Pos].Next;//将NewCell插入为H->Heads[Pos]链表的第一个结点  
		H->Heads[Pos].Next =NewCell;
		H->Heads[Pos].Count ++;//链表中增加了一个新单词 
	}
	else P->Count ++;//关键词已存在 
} 

void Show(HashTable H, double percent)
{
	int diffwordcount =0;//不同的单词数量
	int maxf =0;//最大的词频
	int *diffwords;//存储词频从1到maxf的单词数量
	Position L;
	int i,j,k,lowerbound,count=0;
	for(i=0;i<H->TableSize ;i++)//遍历整个散列表
	{
		diffwordcount+=H->Heads[i].Count ;//遍历所有单链表的头结点,记录不同的单词数量
	 	L = H->Heads[i].Next ;
	 	while(L){
	 		if(maxf<L->Count) maxf =L->Count; //记录所有单词的最大词频maxf 
	 		L= L->Next;
		}
	}
	printf("%d\n",diffwordcount);
	
	diffwords = (int*)malloc((maxf+1)*sizeof(int));
	for(i=0;i<=maxf;i++) diffwords[i]=0;
	for(i=0;i<H->TableSize ;i++){//统计词频从1到maxf的单词数量
		L= H->Heads[i].Next ;
		while(L){
			diffwords[L->Count]++;//该词频增加一个单词 
			L=L->Next;
		}
	} 
	
	lowerbound =(int)(diffwordcount*percent);
	for(i=maxf;i>=1 && count<lowerbound; i--) count+=diffwords[i]; 
	
	for(j=maxf; j>=i ;j--){//对每个词频,按词频从大到小输出单词 
		for(k=0; k<H->TableSize ;k++){
			L =H->Heads[k].Next ;
			while(L){
				if(j==L->Count ) printf("%-15s:%d\n",L->Data ,L->Count ); //发现一个单词的词频与当前词频相等 
				L=L->Next ;
			}
		}
	}
	free(diffwords);
}

void DestroyTable(HashTable H)
{
	int i;
	Position P, Tmp;
	for(i=0; i<H->TableSize ;i++){
		P = H->Heads[i].Next ;
		while(P){
			Tmp =P->Next ;
			free(P);
			P=Tmp;
		}
	}
	free(H->Heads);
	free(H);
}

char shuru[1111];//输入一行英文

int main()
{
	HashTable H;
	int TableSize=100;
	H=CreateTable(TableSize);
	int length=0,wordcount=0,i,k=0;
	int flag=0;//不再输入的标志 
	ElementType word;
	while(gets(shuru)){ //输入一行英文 
		for(i=0;i<strlen(shuru);i++){
			if(shuru[i]=='#'){
				flag = 1;
				goto Pos_1;//跳转到指定符号处 
			}
			else {
				length = GetAWord(shuru,word,i,k);//读取一个单词
				wordcount++;
				InsertAndCount(H,word);//统计word出现次数
				i+=zongchang[k]-1;//这行英文的下一个单词 
				k++;
				printf("%s\t",word); 
			}
		}
	}
	Pos_1:
		Show(H, 10.0/100);//显示词频前10%的所有单词 
		DestroyTable(H); 
	return 0;
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小吴同学·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值