zoukankan      html  css  js  c++  java
  • anyview 数据结构习题集 第3章答案

    ◆3.17③ 试写一个算法,识别依次读入的一个以@
    为结束符的字符序列是否为形如’序列1&序列2′模式
    的字符序列。其中序列1和序列2中都不含字符’&',
    且序列2是序列1的逆序列。例如,’a+b&b+a’是属该
    模式的字符序列,而’1+3&3-1′则不是。
    实现下列函数: 
    Status match(char *str);
    /* 若str是属该模式的字符序列,*/
    /* 则返回TRUE,否则返回FALSE */
    Stack是一个已实现的栈。
    可使用的相关类型和函数:
    typedef char SElemType; // 栈Stack的元素类型
    Status InitStack(Stack &s);
    Status Push(Stack &s, SElemType e);
    Status Pop(Stack &s, SElemType &e);
    Status StackEmpty(Stack s);
    Status GetTop(Stack s, SElemType &e);

    Status match(char *str)  
    /* 若str是属该模式的字符序列,*/  
    /* 则返回TRUE,否则返回FALSE  */  
    {  
        //文档没有说明字符串是以@结尾的  
        //也没有说栈的类型是SqStack,用Stack时编译出错  
        SqStack s;  
        SElemType c;  
        Status flag=1;  
        InitStack(s);  
        char *cur=str;  
        while('&'!=*cur){  
            Push(s,*cur);  
            ++cur;  
        } //入栈  
        ++cur;  
         if(!GetTop(s,c)&&*cur!='@'){flag=0;}//判断栈空  
        while(*cur!='@' ){  
            Pop(s,c);  
            if(c!=*cur){flag=0;break;}  
            ++cur;  
        }//依次出栈匹配  
        if(GetTop(s,c)){flag=0;}//再次判断是否非空  
        return flag;  
    }

    3.18② 试写一个判别表达式中开、闭括号是否配对出现的算法。
    实现下列函数:
    Status MatchCheck(SqList exp);
    /* 顺序表exp表示表达式; */
    /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */
    /* 注:本函数不使用栈 */
    顺序表类型定义如下:
    typedef struct {
    ElemType *elem;
    int length;
    int listsize;
    } SqList; // 顺序表

    Status MatchCheck(SqList exp)  
    /* 顺序表exp表示表达式;                        */  
    /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */  
    /* 注:本函数不使用栈                           */  
    /*****************************/  
    // 此题top指针和cur指针要很仔细地运用,还有判错条件也要小心  
    {  
        ElemType *cur,*top,*base;  
        base=exp.elem;//模拟栈底  
        top=cur=base+1;//模拟栈顶(top)和当前元素(cur)  
        if(')'==*cur){  
            return FALSE;  
        } //判断第一个字符是否为右括号  
        if(0==exp.length){  
            return TRUE;  
        }//判断是否为空顺序表  
        while(cur<=base+exp.length-1){//依次遍历  
            if('('==*cur){//当元素为左括号时  
                if(top!=cur){  
                    *top=*cur;  
                     *cur='0';  
                               
                }  
                ++top;  
            }//top始终指向第二个元素  
    ////////////////////////////  
             else if(')'==*cur){  
                if(top==base){  
                    return FALSE;  
                }  
                if('('==*(top-1)){  
                    *(--top)='0';  
                    *cur='0';  
                }  
            }  
    ////////////////////////////  
            ++cur;  
        }  
        if('0'==*base){return TRUE;}//此处应为base,而不是top  
        return FALSE;     
    }

    ◆3.19④ 假设一个算术表达式中可以包含三种括号:圆括号”(” 和
    “)”,方括号”["和"]“和花括号”{“和”}”,且这三种括号可按任意的
    次序嵌套使用(如:…[…{…}…[…]…]…[…]…(…)…)。编写判别给定表达
    式中所含括号是否正确配对出现的算法(已知表达式已存入数据元素
    为字符的顺序表中)。
    实现下列函数:
    Status MatchCheck(SqList exp);
    /* 顺序表exp表示表达式; */
    /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */
    顺序表类型定义如下:
    typedef struct {
    ElemType *elem;
    int length;
    int listsize;
    } SqList; // 顺序表
    Stack是一个已实现的栈。
    可使用的相关类型和函数:
    typedef char SElemType; // 栈Stack的元素类型
    Status InitStack(Stack &s);
    Status Push(Stack &s, SElemType e);
    Status Pop(Stack &s, SElemType &e);
    Status StackEmpty(Stack s);
    Status GetTop(Stack s, SElemType &e);

    Status MatchCheck(SqList exp)  
    /* 顺序表exp表示表达式;                        */  
    /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */  
    {      
        ElemType *cur=exp.elem;  
        SElemType temp;  
        SqStack s;  
        InitStack(s);  
        if(0==exp.length){return 1;}  
        while(cur<=exp.elem+exp.length-1){  
            if('['==*cur||'('==*cur||'{'==*cur){  
                Push(s,*cur);  
            }  
            else{  
                GetTop(s,temp);    
                if(StackEmpty(s)){//粗心,栈空时返回的是1而不是0  
                    return 0;  
                }  
                  
                else if(']'==*cur&&'['==temp){  
                    Pop(s,temp);  
                }  
                else if(')'==*cur&&'('==temp){  
                    Pop(s,temp);  
                }  
                else if('}'==*cur&&'{'==temp){  
                    Pop(s,temp);  
                }  
                
            }  
            ++cur;  
        }          
        if(StackEmpty(s))return 1;//粗心,栈空时返回的是1而不是0  
        return 0;  
    }

    3.20③ 假设以二维数组g(1..m,1..n)表示一个图像
    区域,g[i,j]表示该区域中点(i,j)所具颜色,其值
    为从0到k的整数。编写算法置换点(i0,j0)所在区域
    的颜色。约定和(i0,j0)同色的上、下、左、右的邻
    接点为同色区域的点。
    实现下列函数:
    void ChangeColor(GTYPE g, int m, int n,
    char c, int i0, int j0);
    /* 在g[1..m][1..n]中,将元素g[i0][j0] */
    /* 所在的同色区域的颜色置换为颜色c */
    表示图像区域的类型定义如下:
    typedef char GTYPE[m+1][n+1];
    Stack是一个已实现的栈。
    可使用的相关类型和函数:
    typedef int SElemType; // 栈Stack的元素类型
    Status StackInit(Stack &s, int initsize);
    Status Push(Stack &s, SElemType e);
    Status Pop(Stack &s, SElemType &e);
    Status StackEmpty(Stack s);
    Status GetTop(Stack s, SElemType &e);

    void ChangeColor(GTYPE g, int m, int n,   
                     char c, int i0, int j0)  
    /* 在g[1..m][1..n]中,将元素g[i0][j0] */  
    /* 所在的同色区域的颜色置换为颜色c    */  
    /* 
    说明:di=1,2,3,4分别为东南西北四个方向,表示的是下一位置在当前位置的哪
    
    个方向! 
    因为数组的下标的性质,只要知道di就能够退回到上一个位置, 
    而如果第一个元素四周都没有同色元素之后(栈空),结束程序 
    */  
    {  
          
        SqStack  S;  
        InitStack(S);  
        int x,y,di;  
        char color;      
        if(i0<=0||i0>m||j0<=0||j0>n){  
            exit(OVERFLOW);  
        }  
        x=i0;  
        y=j0;  
        color=g[x][y];  
        do{  
            if(x>0&&y>0&&x<=m&&y<=n&&color==g[x][y]){  
                di=1;//设置方向为东  
                g[x][y]=c;  
                Push(S,di);  
                y=y+1;//当前位置切换为东边的元素  
            }  
            else{  
                Pop(S,di);  
                switch(di){//当前位置非同色或不合法,设置当前位置为上一位置
    
    (回退)  
                    case 1:--y;break;  
                    case 2:--x;break;  
                    case 3:++y;break;  
                    case 4:++x;break;  
                }  
                ++di;   
                if(di<=4){//若di>4,相当于只回退  
                    switch(di){//切换当前位置到下一位置  
                        case 1:++y;break;//东临  
                        case 2:++x;break;//
                        case 3:--y;break;//西  
                        case 4:--x;break;//
                    }  
                    Push(S,di);  
                }  
            }      
        }while(!StackEmpty(S));  
    }

    ◆3.21③ 假设表达式由单字母变量和双目四则运
    算算符构成。试写一个算法,将一个通常书写形式
    且书写正确的表达式转换为逆波兰式。
    实现下列函数:
    char *RPExpression(char *e);
    /* 返回表达式e的逆波兰式 */
    Stack是一个已实现的栈。
    可使用的相关类型和函数:
    typedef char SElemType; // 栈Stack的元素类型
    Status InitStack(Stack &s);
    Status Push(Stack &s, SElemType e);
    Status Pop(Stack &s, SElemType &e);
    Status StackEmpty(Stack s);
    SElemType Top(Stack s);

    char *RPExpression(char *e)  
    /* 返回表达式e的逆波兰式 */  
    //由于个人水平,折腾了很就才通过  
    //主要思路如下:  
    //1 建立优先级表,符号表,栈中元素对应符号  
    //2 依此读取字符,判断是运算符还是数字,如果数字直接入后缀表达式栈,  
    //如果是运算符,则判断与栈顶元素优先级关系,进行响应操作  
    /* 
    容易犯错的地方 
    1 优先级关系不正确 
    2 当*p优先级低于运算符栈顶时,出栈,但忘了继续比较 
    3 忘了字符串长度应该为length+1,因为最后'\0' 
    变量说明 
    OPTR 运算符栈 
    rpe 后缀表达式栈 
    opera 数组为运算符表 
    list 数组为优先级表 
    pre_optr 记录运算符栈元素的代表数字 
    */  
    {      
        int i=0,j=0,op1,op2,pre=2,count=0;  
        char *p=e,*head,temp,s[100];  
        Stack OPTR,rpe;  
        int pre_optr[10];  
        char opera[7]={'+','-','*','/','(',')','#'};  
        int list[7][7]={{1,1,-1,-1,-1,1,1}  
                        ,{1,1,-1,-1,-1,1,1}  
                        ,{1,1,1,1,-1,1,1}  
                        ,{1,1,1,1,-1,1,1}  
                        ,{-1,-1,-1,-1,-1,0,-2}  
                        ,{1,1,1,1,-2,1,1}  
                        ,{-1,-1,-1,-1,-1,-2,0}};  
        InitStack(OPTR);  
        InitStack(rpe);  
        while(*p){ //计算出转换后表达式的长度  
            if('('!=*p&&')'!=*p){  
                ++count;  
            }  
            ++p;  
        }  
        p=e;  
        Push(OPTR,'#');   
        pre_optr[j]=6;  
        while(*p){//依此读入字符,进行相应处理  
            for(i=0;i<7;++i){  
                if(opera[i]==*p){  
                    break;  
                }  
            }  
            op2=i;  
            if(7==op2){//判断是否为数字  
                Push(rpe,*p);          
            }  
            else{             
                op1=pre_optr[j];  
                pre=list[op1][op2];  
                if(-2==pre){  
                    return ERROR;  
                }  
                else if(1==pre){//优先级大于*p  
                    if(')'!=*p){  
                        while(1==list[op1][op2]){  
                            Pop(OPTR,temp);  
                            --j;  
                            Push(rpe,temp);  
                            op1=pre_optr[j];  
                        }  
                        pre_optr[++j]=op2;//记录栈顶符号  
                        Push(OPTR,*p);  
                    }  
                    else{//如果为右括号  
                        while(Top(OPTR)!='('){  
                            Pop(OPTR,temp);  
                            Push(rpe,temp);  
                            --j;  
                        }  
                        Pop(OPTR,temp);  
                        --j;  
                    }  
                }  
                else if(0==pre){//等于  
                    Pop(OPTR,temp);  
                }  
                else if(-1==pre){//小于  
                    Push(OPTR,*p);  
                    pre_optr[++j]=op2;//记录栈顶符号  
                      
                }  
            }  
            ++p;  
        }//运行到串尾;  
        while(Top(OPTR)!='#'){  
            Pop(OPTR,temp);  
            Push(rpe,temp);  
        }//符号栈中所有元素出栈----转换完成  
                     
        while(!StackEmpty(rpe)){//栈元素逆转----  
            Pop(rpe,temp);  
            Push(OPTR,temp);  
        }  
        p=head=(char *)malloc(count+1);      
        while('#'!=Top(OPTR)){//将栈元素写入字符串  
           Pop(OPTR,temp);  
           *p=temp;  
           ++p;  
        }  
        *p='\0';  
        return head;  
    }

    3.24③ 试编写如下定义的递归函数的递归算法:
    g(m,n) = 0 当m=0,n>=0
    g(m,n) = g(m-1,2n)+n 当m>0,n>=0
    并根据算法画出求g(5,2)时栈的变化过程。
    实现下列函数:

    int G(int m, int n)  
    /* if m<0 or n<0 then return -1. */  
    {  
        if(m<0||n<0){  
            return -1;  
        }  
        if(0==m){  
            return  0;  
        }  
        else {  
            return G(m-1,2*n)+n; //刚开始竟然很白痴地写成G(m-1,2n) - -||    
    
          
        }      
    }

    3.25④ 试写出求递归函数F(n)的递归算法,
    并消除递归:
    F(n) = n+1 当n=0
    F(n) = nF(n/2) 当n>0
    实现下列函数:

    int F(int n)  
    /* if n<0 then return -1. */  
    {  
        if(n<0){  
            return -1;  
        }  
        if(0==n){  
            return 1;  
        }  
        else{  
            return n*F(n/2);  
        }   
    }

    ◆3.28② 假设以带头结点的循环链表表示队列,并且
    只设一个指针指向队尾元素结点(注意不设头指针),
    试编写相应的队列初始化、入队列和出队列的算法。
    实现下列函数:
    Status InitCLQueue(CLQueue &rear);
    Status EnCLQueue(CLQueue &rear, ElemType x);
    Status DeCLQueue(CLQueue &rear, ElemType &x);
    带头结点循环链队列CLQueue的类型为以下LinkList类型:
    typedef struct LNode{
    ElemType data;
    struct LNode *next;
    } LNode, *LinkList;
    typedef LinkList CLQueue;

    Status InitCLQueue(CLQueue &rear)  
    {   
        rear=(CLQueue)malloc(sizeof(LNode));  
        if(!rear){  
            return FALSE;  
        }  
        rear->next=rear;  
        return TRUE;  
    }  
    Status EnCLQueue(CLQueue &rear, ElemType x)  
    {  
        CLQueue head,p;  
        head=rear->next;  
        p=(CLQueue)malloc(sizeof(LNode));  
        if(!p){  
            return FALSE;  
        }   
        p->data=x;      
        p->next=head;  
        rear->next=p;  
        rear=p;  
        return OK;  
    }  
    Status DeCLQueue(CLQueue &rear, ElemType &x)  
    {            
         CLQueue head,p;  
         head=rear->next;  
         if(rear==rear->next){//这里粗心了,忘记考虑队列空的情况  
            return ERROR;  
         }  
         p=head->next;  
         x=p->data;  
         head->next=p->next;  
         free(p);  
         return OK;  
    }

    3.29③ 如果希望循环队列中的元素都能得到利用,
    则需设置一个标志域tag,并以tag的值为0或1来区
    分,尾指针和头指针值相同时的队列状态是”空”还
    是”满”。试编写与此结构相应的入队列和出队列的
    算法,并从时间和空间角度讨论设标志和不设标志
    这两种方法的使用范围(比如,当循环队列容量较
    小而队列中每个元素占的空间较多时,那一种方法
    较好?)。
    实现下列函数:
    Status EnCQueue(CTagQueue &Q, QElemType x);
    Status DeCQueue(CTagQueue &Q, QElemType &x);
    本题的循环队列CTagQueue的类型定义如下:
    typedef char QElemType;
    typedef struct {
    QElemType elem[MAXQSIZE];
    int tag;
    int front;
    int rear;
    } CTagQueue;

    Status EnCQueue(CTagQueue &Q, QElemType x)  
    {  
        if(Q.tag){  
            return ERROR;  
        }  
        Q.elem[Q.rear]=x;  
        if(Q.rear==MAXQSIZE-1){  
            Q.rear=0;  
        }  
        else{  
            ++Q.rear;  
        }   
        if(Q.rear==Q.front){  
            Q.tag=1;  
        }  
        return OK;  
    }  
    Status DeCQueue(CTagQueue &Q, QElemType &x)  
    {      
        if(Q.front==Q.rear&&0==Q.tag){  
            return ERROR;     
        }  
        else{  
            x=Q.elem[Q.front];  
            if(Q.front!=MAXQSIZE-1){  
                ++Q.front;  
            }  
            else{  
                Q.front=0;  
            }  
                          
            if(Q.front==Q.rear){  
                Q.tag=0;  
            }      
        }  
        return OK;  
    }

    ◆3.30② 假设将循环队列定义为:以域变量rear
    和length分别指示循环队列中队尾元素的位置和内
    含元素的个数。试给出此循环队列的队满条件,并
    写出相应的入队列和出队列的算法(在出队列的算
    法中要返回队头元素)。
    实现下列函数:
    Status EnCQueue(CLenQueue &Q, QElemType x);
    Status DeCQueue(CLenQueue &Q, QElemType &x);
    本题的循环队列CLenQueue的类型定义如下:
    typedef char QElemType;
    typedef struct {
    QElemType elem[MAXQSIZE];
    int length;
    int rear;
    } CLenQueue;

    Status EnCQueue(CLenQueue &Q, QElemType x)  
    {  
        if(MAXQSIZE==Q.length){  
            return ERROR;  
        }  
         
        if(MAXQSIZE-1!=Q.rear){  
            ++Q.rear;  
            Q.elem[Q.rear]=x;  
        }  
        else{  
            Q.rear=0;  
            Q.elem[Q.rear]=x;  
        }  
        ++Q.length;  
        return OK;  
    }  
    Status DeCQueue(CLenQueue &Q, QElemType &x)  
    {  
        if(!Q.length){  
            return ERROR;  
        }  
        if(Q.rear+1>=Q.length){  
            x=Q.elem[Q.rear+1-Q.length];  
        }  
        else{  
             x=Q.elem[MAXQSIZE-Q.length+Q.rear+1];  
        }   
        --Q.length;  
        return OK;  
    }

    ◆3.31③ 假设称正读和反读都相同的字符序列为
    “回文”,例如,’abba’和’abcba’是回文,’abcde’
    和’ababab’则不是回文。试写一个算法判别读入的
    一个以’@'为结束符的字符序列是否是”回文”。
    实现下列函数:
    Status Palindrome(char *word);
    /* 利用栈和队列判定字符序列word是否是回文 */
    可使用栈Stack和队列Queue及其下列操作:
    Status InitStack(Stack &S);
    Status Push(Stack &S, ElemType x);
    Status Pop(Stack &S, ElemType &x);
    Status StackEmpty(Stack S);
    Status InitQueue(Queue &Q);
    Status EnQueue(Queue &Q, ElemType x);
    Status DeQueue(Queue &Q, ElemType &x);
    Status QueueEmpty(Queue Q);

    Status Palindrome(char *word)  
    /* 利用栈和队列判定字符序列word是否是回文 */  
    {      
        Stack S;  
        char temp;  
        InitStack(S);  
        char *p=word,*q=word;  
        while(*p!='@'){      
            Push(S,*p);  
            ++p;          
        }      
        while(!StackEmpty(S)){  
            Pop(S,temp);  
            if(temp!=*q){  
                break;  
            }  
            ++q;  
        }  
        if(StackEmpty(S)){  
            return TRUE;  
        }  
        return FALSE;  
    }
  • 相关阅读:
    UINavigationBar 调整
    UILabel根据内容自动调整高度
    [iOS开发]文档导读
    [iOS开发]NSUserDefaults使用注意
    Xcode 断点的使用
    [iOS开发] UIKit Dynamics
    [iOS开发]ShareSDK
    objective-c GCD
    面向对象设计原则
    Go语言学习教程:go语言的包管理
  • 原文地址:https://www.cnblogs.com/hlb430/p/2613061.html
Copyright © 2011-2022 走看看