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;  
}

 

posted @ 2011-05-08 10:46  hlb430  阅读(6011)  评论(0编辑  收藏  举报