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


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

    答:

    分析题目我们可以知道我们可以通过一个栈进行实现。首先,我们规定运算优先级:乘除法优先级大于加减法优先级。其中,对于同一运算符号,前面出现符号优先级大于后面出现的优先级。我们构建一个栈,然后依次读入,如果读入的数字,就把数字送入到数组中。如果读入的的是运算符,如果是空栈就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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    C# 添加、删除、读取Word形状(基于Spire.Cloud.Word.SDK)
    Java 添加、修改、读取、复制、删除Excel批注
    Java 设置Word页边距、页面大小、页面方向、页面边框
    C# 将Word转为PDF、XPS、Epub、RTF(基于Spire.Cloud.Word.SDK)
    Java添加、读取Excel公式
    C# 添加文本、图片到PDF文档(基于Spire.Cloud.SDK for .NET)
    Java 在Excel单元格中应用一种/多种字体样式
    Java 添加、删除、移动、隐藏/显示Excel工作表
    Java 复制Excel工作表
    Java 将Excel转为图片、html、XPS、XML、CSV
  • 原文地址:https://www.cnblogs.com/lightac/p/12832433.html
Copyright © 2020-2023  润新知