词典变位词检索系统【算法实现】

题目描述

在英文中,把某个单词字母的位置(顺序)加以改变所形成的新字词,叫做anagram,不妨译为变位词。譬如said(say的过去式)就有dais(讲台)这个变位词。在中世纪,这种文字游戏盛行于欧洲各地,当时很多人相信一种神奇的说法,认为人的姓名倒着拼所产生的意义可能跟本性和命运有着某种程度的关联。所以除了消遣娱乐之外,变位词一直被很严肃地看待,很多学者穷毕生精力创造新的变位词。本项目要求词典检索系统实现变位词的查找功能。

输入格式

输入包含多组测试数据。
每组数据的第一行是一个整数N(1<=N<=101),表示丑国的州数,当N=0时表示输入结束。
接下来一行包括N个正整数,分别表示每个州的选民数,每个州的选民数不超过100。

输出

对于每组数据输出一行,表示小明至少需要赢得支持的选民数。

样例输入

tea

y

care

n

样例输出

Now counting the words in dictionary
The dictionary is including 3150 words

Now reading......

Now sorting......

输入单词:tea

tea的变位词有:eat ate

是否继续(y,n)?y

输入单词:care

care的变位词有:race

是否继续(y,n)?n


SqList.h

#include
using namespace std;

//线性表顺序存储结构 
template
class SqList
{
protected:
	int count;		//用于计数表元素个数
	int maxSize;	//顺序表最大元素个数
	ET * elems;		//顺序表起始位置指针

public:
	SqList(int sz);	//线性表构造函数
	~SqList();		//线性表析构函数

	//线性表相关操作
	int Length();	//求表长,即表元素个数
	bool Full();	//表是否已满
	bool Empty();	//表是否为空

	void Init(int size = 0);	//初始化线性顺序表,元素个数0,最大元素数size
	void Clear();			//表清空,置元素个数为0
	void Show();			//输出现实表中现有的所有元素
	string CharToString();			//char类型转化成string类型
	void SetElem(int pos, ET &e);		//向表中任意位置pos写入元素e,元素总数加一,pos应属于[1, maxSize]
	void ReSetElem(int pos, ET &e);		//重置表中任意位置pos元素为e,元素总数不变,pos应属于[1, maxSize]
	void GetElem(int pos, ET &e);		//从表中获取第pos元素,写入e中,由e输出
	void Insert(int pos, ET &e);		//向表中第pos个位置插入元素,元素总数加一,pos应属于[1, count+1]
	void DelElem(int pos);				//删除表中第pos个位置的元素.元素减一
	void Copy(SqList&Cop);			//复制函数,将当前表中的内容复制到表Cop中
	void operator = (SqList& cop);	//赋值符重载函数,实现线性表的复制功能
	void CinHelp();			//提示输入函数,用于实现键盘输入交互式操作

};

template
SqList::SqList(int size)
{
	elems = NULL;
	Init(size);
}

template
SqList::~SqList()
{
	delete[]elems;
}


template
int SqList::Length()
{
	return count;
}

template
bool SqList::Full()
{
	return count == maxSize;
}

template
bool SqList::Empty()
{
	return count == 0;
}


template
void SqList::Init(int size)
{
	maxSize = size;
	if (elems != NULL) delete[]elems;
	elems = new ET[maxSize];
	count = 0;
}

template
void SqList::Clear()
{
	count = 0;
}

template
void SqList::Show()
{
	cout << endl << "当前顺序表中共有" << count << "个元素," << endl << "依次为: ";
	for (int curpos = 1; curpos <= count; curpos++)
	{
		cout << elems[curpos - 1] << " ";
	}
	cout << endl;
}

template
string SqList::CharToString()
{
	//cout << endl << "当前顺序表中共有" << count << "个元素," << endl << "依次为: ";
	//const int num = count;
	string word;
	for (int curpos = 1; curpos <= count; curpos++)
	{
		word += elems[curpos - 1];
		//word[curpos - 1] = elems[curpos - 1];
	}
	//	cout << word;
	return word;
}

template
void SqList::SetElem(int pos, ET &e)
{
	if (pos<1 || pos>maxSize)	cout << endl << "操作无效! 请确保输入元素位置小于" << maxSize + 1 << "大于0" << endl;
	else { elems[pos - 1] = e; count++; }		//置入元素表中元素不存在,元素总数加一
}

template
void SqList::ReSetElem(int pos, ET &e)
{
	if (pos<1 || pos>count || count == 0)	cout << endl << "操作无效! 请确保输入元素位置小于" << count + 1 << "大于0" << endl;
	else elems[pos - 1] = e;		//重置表中元素,元素总数不变
}

template
void SqList::GetElem(int pos, ET &e)
{
	if (pos<1 || pos>Length()) cout << endl << "操作无效! 请确保输入元素位置小于" << count + 1 << "大于0" << endl;
	else e = elems[pos - 1];
}

template
void SqList::Insert(int pos, ET &e)
{		//为使一个元素插入顺序表第i个位置后线性表仍保持顺序,需先将i之后的所有元素均向后移动一位,再插入i
	int len = Length();
	ET tmp;

	if (Full())	cout << endl << "插入操作无效! 线性表已满 共" << count << "个元素" << endl;
	else if (pos<1 || pos>len + 1 || pos > maxSize) cout << endl << "操作无效! 请确保输入元素位置小于" << len + 1 << "大于0" << endl;
	else
	{
		for (int i = len; i > pos; i--)
		{
			GetElem(i - 1, tmp);
			ReSetElem(i, tmp);		//后移为重置元素
		}
		SetElem(pos, e);			//置入新元素
	}
}

template
void SqList::DelElem(int pos)
{
	int len = Length();
	ET tmp, e;

	if (pos<1 || pos>len) cout << endl << "删除失败! 请确保删除元素位置小于" << len + 1 << "大于0" << endl;
	else
	{
		GetElem(pos, e);		//删除第i个元素,只需将i后元素均向前移一位
		for (int i = pos; i < len; i++)
		{
			GetElem(i + 1, tmp);
			ReSetElem(i, tmp);
		}
		count--;		//元素总数减一
		cout << endl << "第" << pos << "个元素" << e << "删除成功" << endl;
	}
}


template
void SqList::Copy(SqList&Cop)
{	//复制函数
	int pos = 1;
	ET e;
	Cop.Clear();
	while (pos <= count && pos <= Cop.maxSize)	//当待复制元素未复制完且Copy中还有空间时继续复制
	{
		GetElem(pos, e);
		Cop.SetElem(pos, e);
		pos++;
	}
	if (pos - 1 != count) cout << "此线性表空间不足,共需" << count << "个元素空间";
}

template
void SqList::operator = (SqList& cop)
{	//赋值符“ = ”重载
	int pos = 1;
	ET e;
	while (pos <= cop.count && pos <= maxSize)	//当线性表cop中元素未复制完,且当前线性表中还有空间时继续复制
	{
		cop.GetElem(pos, e);
		SetElem(pos, e);
		pos++;
	}
	if (pos - 1 != cop.count) cout << endl << "此线性表空间不足,共需" << cop.count << "个元素空间" << endl;
}

template
void SqList::CinHelp()
{
	int choice = 1, pos;
	ET elem;
	while (choice)
	{
		cout << endl << "请选择线性表相关操作:" << endl << endl << "1.输入所有元素  2.插入表元素  3.删除表元素  4.修改元素  5.清空" << endl << endl << "选择并以Enter确认:";
		cin >> choice;
		switch (choice)
		{
		case 1:		//输入所有元素
			pos = count + 1;
			cout << endl << "请依次输入" << maxSize - count << "个表元素  空格间隔 Enter确认: " << endl;
			while (Full() == 0) { cin >> elem; SetElem(pos, elem); pos++; }
			Show();
			break;

		case 2:		//插入表元素
			cout << endl << "请依次输入表元素和位置  空格间隔Enter确认: ";
			cin >> elem >> pos;
			Insert(pos, elem);
			Show();
			break;

		case 3:		//删除表元素
			cout << endl << "请输入要删除第几个元素,Enter确认: ";
			cin >> pos;
			DelElem(pos);
			Show();
			break;

		case 4:		//修改元素
			cout << endl << "请依次输入表元素和位置 空格间隔Enter确认: ";
			cin >> elem >> pos;
			ReSetElem(pos, elem);
			Show();
			break;

		case 5:		//清空
			Clear();
			Show();
			break;
		}
		cout << endl << "0.退出	1.继续   选择: ";
		cin >> choice;
		cout << endl << endl << endl;
	}
}


DictionaryAnagramSearchSystem.h

#include
#include
#include 
#include 
#include "SqList.h"

using namespace std;
//为提高程序的可读性,我们将词典变位词检索系统封装成类DictionaryAnagramSearchSystem,类及相关函数具体声明如下:
//词典变位词检索系统类
class DictionaryAnagramSearchSystem
{
private:
	//词典变位词检索系统类的数据成员
	string * dict;
	int size;
	int BinSerach(string array[], string val);//单词检索
public:
	DictionaryAnagramSearchSystem();//构造函数
	virtual ~DictionaryAnagramSearchSystem();//析构函数
	friend istream &operator>>(istream &inStream, string &inStr);//重载输入运算符>>
	friend ostream &operator<<(ostream &outStream, const string &outStr);//重载输出运算符<<
	void AllArrageCreateAnagram(string word, string &anagram, int curLen = 0);//由word各字符的全排列产生变位词
}


DictionaryAnagramSearchSystem_proxy.h

#include "DictionaryAnagramSearchSystem.h"

int DictionaryAnagramSearchSystem::BinSerach(string array[], string val)
{
	//单词遍历检索
	if (0 == size)
		return LONG_MIN; //最小的32位数(-2147483648).
	for (int i = 0; i < size; i++)
	if (val == array[i])
	
	return size;
}

//构造函数DictionaryAnagramSearchSystem()首先打开词典文件diction.txt,然后统计词典包含的单词数,为词典数据成员dict分配存储空间,再将词典文件中的单词读入dict,然后进行排序。
DictionaryAnagramSearchSystem::DictionaryAnagramSearchSystem()
{
	ifstream dictFile("diction.txt");//词典文件
	if (!dictFile.good()) throw "open file failed";//抛出异常
	//判断文件打开状态:成功or失败
	size = 0; string str;
	cout << "Now counting the words in dictionary" << endl;
	
	while (dictFile.good()){//统计单词数量
		
		getline(dictFile, str);
		
		size++;
	}
	cout << "The dictionary is including " << size << " words" << endl;
	cout << "Now reading......" << endl;
	dict = new string[size];//分配存储空间
	dictFile.clear();//清除eof标志
	dictFile.seekg(0);//定位到文件头
	for (int pos = 0; pos < size; pos++)getline(dictFile, dict[pos]);//读入单词
	cout << "Now sorting......" << endl;
	sort(dict, dict + size);//单词排序
	//for (int pos = 0; pos < size; pos++)cout << dict[pos] << endl;
	dictFile.close();//关闭文件
}



//查询一个单词所有变位词的最直接方法就是找出单词的所有排列,在词典中查找排列,如果存在,就输出。可采用对此树进行先序遍历方式进行遍历,并用回溯法进行递归产生从n个字符的全排列,输出其中词典出现的单词
void DictionaryAnagramSearchSystem::AllArrageCreateAnagram(string word, string &anagram, int curLen)
{

	if (curLen == anagram.length() - 1)
	{
		//产生一个可能的变位词
		if (anagram != word&&BinSerach(dict, anagram) <
			size)
			cout << anagram << " ";//输出变位词
	}
	else
	{
		//先序遍历,anagram[curLen...anagram.length()-1]有多个排列,递归生成排列
		for (int pos = curLen; pos < (int)anagram.length(); pos++)
		{//依次取出字符
			char ch = anagram[pos];
			anagram[pos] = anagram[curLen];
			anagram[curLen] = ch;//交换字符
			AllArrageCreateAnagram(word, anagram, curLen + 1);//递归的生成排列
			anagram[curLen] = anagram[pos];
			anagram[pos] = ch;//交换字符
		}

	}
}

//为使程序的可读性强,我们在DictionaryAngramSearchSystem类中定义了两个友元函数,重载输入运算符<<与输入运算符>>用于输出或输入单词
ostream &operator<<(ostream &outStream, const string &outStr){
	cout << outStr.c_str();
	return outStream;
}

istream &operator>>(istream &inStream, string &inStr){
	SqList temp(20);//临时线性表
	int pos = 0;//初始线性表长度
	char ch = inStream.get();//跳过空格及制表符获取一字符
	inStream.putback(ch);//回送输入流
	if (ch == '\n')
	ch = inStream.get();
	while ((ch = inStream.get()) != '\n')
	{
		temp.Insert(++pos, ch);//字符追加到线性表
	}
	
	string answer(temp.CharToString());//构造串
	inStr = answer;//返回串
	return inStream;//返回输入流对象
}


DictionaryAnagramSearchSystem.cpp

#include"DictionaryAnagramSearchSystem_proxy.h"
void  main()
{
	DictionaryAnagramSearchSystem dic;
	string word;
	do{
		cout << "输入单词:";
		cin >> word;
		cout << word << "的变位词有:";
		dic.AllArrageCreateAnagram(word, word, 0);
		cout << endl << "是否继续(y,n)?";
	} while (getchar() == 'y');
}


diction.txt

tea
eat
ate

你可能感兴趣的:(JAVA算法)