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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM