AVL树实现对英文字典的查找

一、需求分析

1、问题描述

设计一个程序实现对英文字典的查找。

2、功能需求

用户输入希望查找的英文单词,经程序在预存的英文字典中搜索,并将结果输出在屏幕上(待查找单词在字典中被收录,输出该单词中文释义,待查找单词在字典中未被收录,予以提示)。
程序执行的命令包括:
(1)、程序运行,提示用户输入单词;
(2)、用户输入希望查找的英文单词;
(3)、系统进行搜索,并将结果输出在屏幕上;
(4)、结束。

二、概要设计

1、 问题的抽象数据类型分析

本题要实现对英文字典的查找,需要构造两个抽象数据类型。
一个是英文字典。对于一个结点(结构体)即代表字典中收录的一个英文单词,数据域分为两部分,一部分是单词,另一部分是单词释义。一个英文字典由很多英文单词(即结点)组成,可直接用stl中的内置类型vector容器进行存储。
另一个是高效的搜索结构。其中要存英文单词以供查找,同时,从中查找到待查单词后,要到已构建的英文字典中找该单词对应的释义。因此,要建立英文字典与搜索结构之间的关系。英文字典是利用vector存储的,通过下标可以确实唯一一个英文单词。故可在搜索结构数据域中增加一部分,来记录单词在字典中存储的下标,从而可以快速获取其释义。

2、存储结构设计

1)、存储结构的确定
高效的查找方法,如分块查找、AVL树、B树、哈希表,各有各的特点。我认为AVL树(高度平衡的二叉搜索树)较为高效,选用该存储结构。其搜索时间代价(不论成功还是失败)都不超过树的高度,又因插入时通过平衡化旋转,保证了树的平衡,使得树的高度较小,因而效率较高。
2)、设计AVL树结点
在这里插入图片描述
3)、逻辑操作设计

(1)、构造一个空的AVL树
(2)、在AVL树中插入新的结点
(3)、在AVL树中进行搜索
(4)、读取英文字典的txt文档并存储
(5)、利用英文字典构造AVL树
(6)、查找单词并将结果输出

三、详细设计

1、字典结构体的定义:

struct Dictionary
{
	string word;
	string meaning;
	Dictionary():word(""),meaning(""){}
};

2、AVL树结点的定义:

struct AVLNode
{
	string data;
	int bf;
	int num;
	AVLNode *left, *right;
	AVLNode():data(""),left(NULL),right(NULL),bf(0),num(-1){}
	AVLNode(string s,int n,AVLNode *l=NULL,AVLNode *r=NULL)
		:data(s),left(l),right(r),bf(0),num(n){}
};

3、AVL树类的定义:

class AVLtree
{
private:
	AVLNode *root;
	void RotateL(AVLNode *&ptr);
	void RotateR(AVLNode *&ptr);
	void RotateLR(AVLNode *&ptr);
	void RotateRL(AVLNode *&ptr);
public:
	AVLtree() :root(NULL) {}
	~AVLtree() {};
	AVLNode * getRoot()
	{
		return root;
	}
	bool Insert(AVLNode *&ptr, string &s,int n);
	int Search(const string s, AVLNode *ptr);
};

int AVLtree::Search(const string s, AVLNode *ptr)
{
	if (ptr == NULL) return -1;
	else if (s < ptr->data) return Search(s, ptr->left);
	else if (s > ptr->data) return Search(s, ptr->right);
	else return ptr->num;
}

void AVLtree::RotateL(AVLNode *&ptr)
{
	AVLNode *subL = ptr;
	ptr = subL->right;
	subL->right = ptr->left;
	ptr->left = subL;
	ptr->bf = subL->bf = 0;
}

void AVLtree::RotateR(AVLNode *&ptr)
{
	AVLNode *subR = ptr;
	ptr = subR->left;
	subR->left = ptr->right;
	ptr->right = subR;
	ptr->bf = subR->bf = 0;
}

void AVLtree::RotateLR(AVLNode *&ptr)
{
	AVLNode *subR = ptr, *subL = subR->left;
	ptr = subL->right;
	subL->right = ptr->left;
	ptr->left = subL;
	if (ptr->bf <= 0) subL->bf = 0;
	else subL->bf = -1;
	subR->left = ptr->right;
	ptr->right = subR;
	if (ptr->bf == -1) subR->bf = 1;
	else subR->bf = 0;
	ptr->bf = 0;
}

void AVLtree::RotateRL(AVLNode *&ptr)
{
	AVLNode *subL = ptr, *subR = subL->right;
	ptr = subR->left;
	subR->left = ptr->right;
	ptr->right = subR;
	if (ptr->bf >= 0) subR->bf = 0;
	else subR->bf = 1;
	subL->right = ptr->left;
	ptr->left = subL;
	if (ptr->bf == 1) subL->bf = -1;
	else subR->bf = 0;
	ptr->bf = 0;
}

bool AVLtree::Insert(AVLNode *&ptr, string &s,int n)
{
	AVLNode *pr = NULL;
	AVLNode *p = ptr, *q;
	int lable;									//标签
	stack<AVLNode*> st;						//栈记录查找路径,当插入元素后,通过出栈回溯,平衡化祖先节点
	while (p != NULL)
	{
		if (s == p->data) return false;			//存在值为x的结点,不插入
		pr = p;									//pr存储插入节点的父结点
		st.push(pr);							//存储搜索路径
		if (s < p->data) p = p->left;
		else p = p->right;
	}
	p = new AVLNode(s,n);
	if (p == NULL) 
	{
		cerr << "存储空间分配错误!" << endl; exit(1);
	}
	if (pr == NULL)
	{
		ptr = p;
		return true;							//空树,新插入结点为根节点
	}
	if (s < pr->data)
	{
		pr->left = p;
	}
	else
	{
		pr->right = p;
	}
	while (st.empty() == false) //将插入新结点后得到的树重新平衡化
	{				
		pr = st.top();
		st.pop();
		if (p == pr->left) pr->bf--;
		else pr->bf++;
		if (pr->bf == 0)break;					//插入后父结点平衡因子为0,无需调整,直接退出
		if (abs(pr->bf) == 1) p = pr;           //插入后父结点平衡因子为1,回溯判断
		if (abs(pr->bf) == 2) 
		{
			lable = (pr->bf < 0) ? -1 : 1;			//记录父结点平衡因子符号,判断单旋还是双旋
			if (p->bf == lable)//两结点平衡因子同号,单旋
			{					
				if (lable == 1)RotateL(pr);
				else RotateR(pr);
			}
			else //两节点平衡因子异号,双旋
			{									
				if (lable == 1) RotateRL(pr);
				else RotateLR(pr);
			}
			break;
		}
	}
	if (st.empty())
	{
		ptr = pr;
	}
	else//将AVL树重新链接好
	{										
		q = st.top();
		if (q->data > pr->data) 
		{
			q->left = pr;
		}
		else
		{
			q->right = pr;
		}
	}
	return true;
}

4、主函数:

void main()
{
	vector<Dictionary> VecDic;
	AVLtree at;
	int i = 0;
	Dictionary dic;
	string s1, s2;
	ifstream ifile;
	ifile.open("English dictionary.txt");
	if (!ifile)
	{
		cout << "无法打开 English dictionary.txt !" << endl;
		exit(1);
	}
	VecDic.empty();
	while (ifile >> s1 >> s2)
	{
		dic.word = s1;
		dic.meaning = s2;
		VecDic.push_back(dic);
	}
	ifile.close();
	AVLNode *ptr = at.getRoot();
	for (i = 0; i < VecDic.size(); i++)
	{
		at.Insert(ptr, VecDic[i].word, i);
	}
	cout << "欢迎使用Snoopy的英文字典(该字典只收录了以a开头的单词)" << endl;
	cout << "请输入您希望查找的单词:";
	string s;
	cin >> s;
	int r = at.Search(s, ptr);
	if (r == -1)
		cout << "抱歉,此字典未收录您希望查找的单词!" << endl;
	else
		cout << "您希望查找的单词" << VecDic[r].word << "的释义为" << VecDic[r].meaning << endl;
	cout << "欢迎您再次使用!" << endl;
	system("pause");

}

四、测试实例

在这里插入图片描述
在这里插入图片描述
结论:测试结果正确。

PS:读入的English dictionary.txt长这个样子

在这里插入图片描述
关于为什么只有a开头的单词,是因为我太懒了,没有收集整理其他字母开头单词的txt文档(狗头)。要扩充的话,大噶自己整理就阔以啦。(唔,txt俺就不放了8~)

Java课程设计实训大作业:记事本+简易计算器+聊天系统+日历+中英查询 基础任务一:设计日历软件 根据如下图,综合运用GUI编程、事件处理、Calendar类应用等知识设计一款月历,要求能通过输入(或选择)年月的方式正确显示当前月份的所有日期。 基础任务二:设计中英查询软件 根据Java面向对象程序设计相关理论,及GUI编程、事件处理、数据库编程等技术,设计一个如下图所示的“中英文释义查询”程序。输入英文单词,查询数据库将对应的中文显示在下框中;输入中文,查询数据库将对应的英文单词显示在下框中。 提升任务三:设计简易记事本软件 1.使用Java图形界面组件设计记事本软件的界面,参考如图所示。 2.程序代码规范,逻辑正确,能够正常运行。 3.“文件”菜单,包括“新建”、“打开”、“保存”、“另存为”和“退出”等功能。 提升任务四:设计简易计算器软件 1.使用Java图形界面组件设计软件,界面如图所示。 2.软件能够满足基本的“加、减、乘、除”等运算要求。 3.程序代码清晰,语法规范,结构合理,逻辑正确。 进阶任务五:自选主题开发一个应用软件(如在线聊天系统,学籍管理系统等)下面给的软件界面只是参考,同学们可以根据自己的想法进行设计。 1.软件界面美观、功能完善软件,导航清晰,操作方便,使用菜单栏、工具栏、布局管理器、按钮、表格等多种Java图形界面组件。 2.程序代码清晰,语法规范,结构合理,逻辑正确。 3.功能完善,程序代码优化,执行效率高,具有较好可维护性和可扩展性。 4.软件功能设计具有一定的难度和创意。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值