数据结构与算法参考答案(第五周)
一、假设表达式由单字母变量和双目四则运算算符构成。试写一个算法,将一个通常书写形式且书写正确的表达式转换为逆波兰式。
答:
分析题目我们可以知道我们可以通过一个栈进行实现。首先,我们规定运算优先级:乘除法优先级大于加减法优先级。其中,对于同一运算符号,前面出现符号优先级大于后面出现的优先级。我们构建一个栈,然后依次读入,如果读入的数字,就把数字送入到数组中。如果读入的的是运算符,如果是空栈就push这个运算符,如果非空,开始循环,取出栈顶元素。将栈顶元素与读入的该运算符进行比较,如果栈顶的运算符优先级高,弹出栈顶运算符,就把该运算符送入数组。循环执行,遇到此时栈顶运算符优先级比判断运算符优先级低时,结束循环。最后返回得到的char*类型的字符数组便是逆波兰式。
该算法实现的伪代码如下:
/*
函数名称:将一般运算表达式转换为逆波兰表达式
函数传入参数:需要转换的表达式
函数返回值:char*类型 转换后得到的逆波兰表达式
*/
char * InversePolandExpression(char term[]) {
Stack S; //声明一个用于存放运算符的栈
char e; //用于获取栈顶元素;
char *ans; //用于返回答案
int i = 0, j = 0; //循环变量
while(term[i] != '\0') {
if(term[i] <= '9' && term[i] >= '0') { //如果读到的是数字
ans[j++] = term[i];
}
else {
while(!Empty(S)) { //如果栈S不为空
GetTop(S, &e); //获取栈顶元素
if(Priority(e, term[i])) //如果栈顶元素优先级更高
{
Pop(&S, &e); //弹出栈顶元素
ans[j++] = e; //送入数组
}
else{
break;
}
Push(&S, term[i]);
}
}
i++;
}
S.clear(); //清空栈
ans[j] = '\0';
return ans; //返回逆波兰表达式
}
算法分析:本算法时间复杂度为nlogn。空间占用一个栈的一个字符类型数组的空间。总的来说是用栈实现的较为高效的算法。
二、假设称正读和反读都相同的字符序列为“回文”,例如,’abba’和’abcba’是回文,’abcde’和’ababab’则不是回文。试写一个算法算法判别读入的一个以’@’为结束符的字符序列是否是“回文”。
答:
分析题目我们容易知道我们可以用一个栈实现回文串的判定。我们把输入字符的一半压入栈中(假设是奇数个字符我们压入(n-1)/2个)。然后如果是奇数个字符,我们从压入之后的第二个开始判断,偶数个直接开始判断。将栈顶元素与此时遍历到的元素进行比较。如果相等,弹出栈顶元素,继续进行比较。如果不相等,直接返回false代表不是“回文”。当遍历完成之后,最后的栈为空,返回true代表它是“回文”。
该算法实现的伪代码如下:
/*
函数名称:判断字符串是否是回文串
传入参数:str需要判断的字符串
返回值:布尔型 返回true代表是回文串 返回false代表不是回文串
*/
bool IsPalindromeString(char *str) {
Stack S;
int i = 0;
for(int i = 0; i < (str.size())/ 2; ++i) {
S.Push(str[i]);
//将字符串的一半压入栈中
}
if(str.size() & 1) { //如果字符串的长度为奇数
i++;
}
char e; //获得栈顶元素
for(; i < str.size(); ++i) {
GetTop(&S, &e); //获得栈顶元素
if(str[i] == e) { //判断栈顶元素与此时遍历的元素是否相等
Pop(&S, &e);
continue; //继续执行循环
}
return false;
}
return true;
}
算法分析:本算法的时间复杂度为O(n)。空间占用一个栈的空间。总的来说,是一个很高效的算法。
三、试利用循环队列编写求k阶斐波那契序列中前n+1项(f0,f1,...,fn)的算法,要求满足:fn≤max而fn+1>max,其中max为某个约定的常数。(注意:本题所用的循环队列的容量仅为k,则在算法执行结束时,留在循环队列中的元素应是所求k阶斐波那契序列中的最后k项fn-k+1,...,fn)。
答:
由题目分析可知,我们可以通过一个循环链表实现该算法。传入的参数是k,最终得到的数组f以及数组元素的个数n和约定的常数max。首先当k小于2或者max<0时,出现错误输入,应当返回error。然后由k阶斐波拉契数列相关知识,我们需要把队列中前k-1项置为0,第k项置为1。然后,将f数组初始化为上述情况。然后执行循环,我们设置临时变量进行判断,temp为此时循环队列中的元素之和。循环的终止条件为temp>max。通过不断改变尾指针进行循环。最后留在循环队列中的元素便是最后k项。
该算法实现的伪代码如下:
Status GetKFibolacciSequence(int f[], int k, int max, int &n) {
if(max < 0 || k < 2) {
return error;
}
int n;
Queue Q;
initQueue(&Q); //创建一个空队列
//初始化
for(int i = 0; i < k - 1; ++i) {
EnQueue(&Q, 0);
}
EnQueue(&Q, 1);
for(int i = 0; i < k; ++i) {
f[i] = Q.base[i];
}
n = k - 2;
do{
n++;
int temp = 0;
//求和
for(int i = 0; i < Q.length; ++i) {
temp += Q.base[i];
}
fib[n + 1] = temp;
Q.base[Q.rear] = temp; //插入尾部
Q.rear = (Q.rear + 1) % MAXQSIZE;
//更新尾部
}while(temp<=max);
return ok;
}
算法分析:该算法使用了二重循环。在do...while语句中进行循环队列求和。然后实现了队列的不断更新,当运行结束后,便得到所求结果。该算法占用了一个队列的空间。对于这个问题来说,这是一个高效的算法。

浙公网安备 33010602011771号