数据结构与算法参考答案(第五周)

一、假设表达式由单字母变量和双目四则运算算符构成。试写一个算法,将一个通常书写形式且书写正确的表达式转换为逆波兰式。

答:

分析题目我们可以知道我们可以通过一个栈进行实现。首先,我们规定运算优先级:乘除法优先级大于加减法优先级。其中,对于同一运算符号,前面出现符号优先级大于后面出现的优先级。我们构建一个栈,然后依次读入,如果读入的数字,就把数字送入到数组中。如果读入的的是运算符,如果是空栈就push这个运算符,如果非空,开始循环,取出栈顶元素。将栈顶元素与读入的该运算符进行比较,如果栈顶的运算符优先级高,弹出栈顶运算符,就把该运算符送入数组。循环执行,遇到此时栈顶运算符优先级比判断运算符优先级低时,结束循环。最后返回得到的char*类型的字符数组便是逆波兰式。

该算法实现的伪代码如下:

/*
    函数名称:将一般运算表达式转换为逆波兰表达式
    函数传入参数:需要转换的表达式
    函数返回值:char*类型 转换后得到的逆波兰表达式
*/
char * InversePolandExpression(char term[]) {
    Stack S; //声明一个用于存放运算符的栈
    char e; //用于获取栈顶元素;
    char *ans;  //用于返回答案
    int i = 0, j = 0; //循环变量
    while(term[i] != '') {
        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] = '';
    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(f0f1...fn)的算法,要求满足:fn≤maxfn+1>max,其中max为某个约定的常数。(注意:本题所用的循环队列的容量仅为k,则在算法执行结束时,留在循环队列中的元素应是所求k阶斐波那契序列中的最后kfn-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语句中进行循环队列求和。然后实现了队列的不断更新,当运行结束后,便得到所求结果。该算法占用了一个队列的空间。对于这个问题来说,这是一个高效的算法。

作者:LightAc
出处:https://www.cnblogs.com/lightac/
联系:
Email: dzz@stu.ouc.edu.cn
QQ: 1171613053
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/lightac/p/12832433.html