【问题描述】
3.读取数据与输出结果
如何通过一系列堆栈操作实现会问构词法呢?有两种堆栈的操作,将单词TROT转换成TORT.
[
i i i i o o o o
i o i i o o i o
]
i代表入栈,o代表出栈。对给定的单词对,编程实现堆栈操作,将第一个单词转换为第二个单词。
有多行输入。每两行的第一行是源单词(不包括换行符),第二行是目标单词(也不包括换行符)。由文件结束符标志输入结束。
对每对单词,有多种有效方法从源单词产生目标单词,将每种方法的i和o操作排序输出,并以[ ]分隔。排序方法是字典序。每个i和o之后都有一个空格。
堆栈操作:
堆栈是一种数据存储方法,它有两种操作:
Push——插入一个数据项;
Pop——检索最近插入的数据项。
堆栈初始时是空栈。用字符i表示Push操作,字符o表示Pop操作。对于一个给定的单词,每个字符的出入栈顺序有些是合法的,有些是非法的;当然不能对空栈进行出栈操作。
输入样例:
madam
adamm
bahama
bahama
输出样例:
[
i i i i o o o i o o
i i i i o o o o i o
i i o i o i o i o o
i i o i o i o o i o
]
[
i o i i i o o i i o o o
i o i i i o o o i o i o
i o i o i o i i i o o o
i o i o i o i o i o i o
]
【算法分析】
1.数据结构
string a, b; //源单词和目标单词
stack<char> build; //构造目标字符串
vector<char> operate; //记录出入栈操作
int length; //字符串a的长度
2.使用回溯算法,构造目标单词
由源单词构造目标单词是,由于入栈和出栈的方式不同,构造的方法就不同。采用完全二叉树的搜索结构,即回溯算法,能够将每一种可能性都搜索出来。为了将每种方法的i和o操作排序输出,在搜索时只要先搜索入栈,然后搜索出栈的操作方法就可以。
//形参iPush记录入栈操作的次数,形参iPop记录出栈操作次数
void dfs(int iPush, int iPop)
{
//当出入栈操作的次数刚好为源单词的长度时,目标单词构造完毕,输出操作序列
if(iPush == length && iPop == length) {
for(int i = 0; i < operate.size(); i ++)
cout << operate[i] << " ";
cout << endl;
}
//入栈操作
if(iPush + 1 <= length)
{
build.push(a[iPush]); //将当前字符入栈
operate.push_back('i'); //记录入栈操作
dfs(iPush + 1, iPop); //搜索下一个位置
build.pop(); //恢复刚刚入栈的字符,便于下一个搜索
operate.pop_back(); //恢复入栈操作
}
//出栈操作
if(iPop + 1 <= iPush && iPop + 1 <= length && build.top() == b[iPop])
{
char tc = build.top();
build.pop(); //将当前字符出栈
operate.push_back('o'); //记录出栈操作
dfs(iPush, iPop + 1); //搜索下一个位置
build.push(tc); //恢复刚刚出栈的字符,便于下一个搜索
operate.pop_back(); //恢复出栈操作
}
}
3.读取数据与输出结果
int main()
{
while(cin >> a >> b)
{
length = a.length();
cout << "[" << endl;
dfs(0, 0);
cout << "]" << endl;
}
return 0;
}