【王道数据结构课后习题代码练习完整版】栈和队列

3.1.4-3 假设以I和O分别表示入 栈和出栈操作,栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,可以操作的序列称为合法序列,否则称为非法序列。

#include 
//假设以I和O分别表示入栈和出栈操作,栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,可以操作的序列称为合法序列,否则
//称为非法序列。

//算法思想:一次读取字符串中的字符,并用i和j记录入栈和出栈的次数,如出栈的次数大于入栈的次数,则非法;等到字符串遍历完毕,如入栈的次数和出栈的
//次数不相等,则栈不为空,也为非法。
bool judge(char A[]){
    int i=0,j=0,k=0;//分别记录入栈和出栈的次数,k为遍历下标
    while(A[k]){ //字符串结束符的值为0
        switch(A[i]){ //如扫描结果为I,则break跳出switch循环,如扫描结果为O,则要比较i和j的大小,减少了if判断的次数
            case 'I':i++;break;
            case 'O':j++;
            if(j>i){
                return false;
            }
        }
        k++;
    }
    if(i!=j){
        return false;
    }
    return true;
}


int main() {
    char A[10];
    bool ret;
    printf("input c:\n");
    scanf("%s",A);
    printf("%s\n",A);
    ret=judge(A);
    if(ret){
        printf("right string\n");
    }else{
        printf("wrong string\n");
    }
    return 0;
}

输出结果:
input c:
IIOOO
IIOOO
wrong string

进程已结束,退出代码为 0

3.1.4-4 设单链表的表头指针为L,结点结构由data和next两个域构成,其中data为字符型。
请设计算法判断该链表的全部n个字符是否中心对称。

3.1.4-5 设有两个栈S1,S2都采用顺序栈方式,并且共享一个存储区 [0……MAXSIZE-1],为了尽量利用空间,减少溢出的可能,可采用栈顶相向、迎面增长的存储方式,编写程序实现S1,S2有关入栈和出栈的操作。

#include 

//共享栈的基本操作
#define MaxSize 10
typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    int top[2];//top为两个栈顶指针
}SqStack;

//初始化栈
void InitStack(SqStack &S){
    S.top[0]=-1;//左边的s1栈顶指针
    S.top[1]=MaxSize;//右边的s2栈顶指针
}

//入栈判栈满,出栈判栈空
//入栈
bool Push(SqStack &S,int i,ElemType x){ //i为栈号,i=0表示左边的s1栈,i=1表示右边的s2栈,x是入栈元素
    if(i<0||i>1){
        printf("wrong input\n");
        return false;
    }
    if(S.top[1]-S.top[0]==1){ //入栈判栈满
        printf("the stack is full\n");
        return false;
    }
    if(i==0){
        S.data[++S.top[0]]=x;
    }else{
        S.data[--S.top[1]]=x;
    }
    return true;
}


//出栈
bool Pop(SqStack &S,int i,ElemType &x){
    if(i<0||i>1){
        printf("wrong output");
        return false;
    }
    if(i==0){
        if(S.top[0]==-1){ //出栈判栈空
            printf("the stack s1 is empty\n");
            return false;
        }
        x=S.data[S.top[0]--];
    }else{
        if(S.top[1]==MaxSize){
            printf("the stack s2 is empty\n");
            return false;
        }
        x=S.data[S.top[1]++];
    }
    return true;
}


//读取栈顶元素
bool GetTop(SqStack S,int i,ElemType &x){ //x保存栈顶元素的值
    if(i<0||i>1){
        printf("wrong stack\n");
        return false;
    }
    if(i==0){
        if(S.top[0]==-1){
            printf("the stack s1 is empty\n");
            return false;
        }
        x=S.data[S.top[0]];
    }else{
        if(S.top[1]==MaxSize){
            printf("the stack s2 is empty\n ");
            return false;
        }
        x=S.data[S.top[1]];
    }
}


int main() {
    SqStack S;
    InitStack(S);
    Push(S,0,1);
    Push(S,0,2);
    Push(S,0,3);
    Push(S,0,4);
    Push(S,1,1);
    Push(S,1,2);
    Push(S,1,3);
    ElemType x;
    bool ret;
    ret=Pop(S,0,x);
    printf("x is:%d\n",x);
    ret=Pop(S,1,x);
    printf("x is:%d\n",x);
    ret= GetTop(S,0,x);
    printf("x is:%d",x);
    return 0;
}

输出结果:
x is:4
x is:3
x is:3
进程已结束,退出代码为 0

3.2.5-1 若希望队列中的元素都能得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的状态是空还是满,试编写与此结构相对应的入队和出队算法

#include 

//若希望队列中的元素都能得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的状态是空还是满,
//试编写与此结构相对应的入队和出队算法
#define MaxSize 20
typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    int front,rear;
    int tag;//tag=0,表示因删除操作导致front=rear,则队列为空;tag=1,表示因插入操作导致front=rear,则队列为满
}SqQueue;

//队列初始化
void InitStack(SqQueue &Q){
    Q.front=Q.rear=0;//front指向队头元素,rear指向队尾元素的下一个元素
    Q.tag=0;
}

//入队
bool EnQueue(SqQueue &Q,ElemType x){
    if(Q.rear==Q.front&&Q.tag==1){
        printf("the queue is full\n");
        return false;
    }
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MaxSize;
    Q.tag=1;
    return true;
}

//出队
bool DeQueue(SqQueue &Q,ElemType &x){
    if(Q.rear==Q.front&&Q.tag==0){
        printf("the stack is empty\n");
        return false;
    }
    x=Q.data[Q.front];
    Q.front=(Q.front+1)%MaxSize;
    Q.tag=0;
    return true;
}



int main() {
    SqQueue Q;
    InitStack(Q);
    EnQueue(Q,1);
    EnQueue(Q,2);
    EnQueue(Q,3);
    EnQueue(Q,4);
    ElemType x;
    bool ret;
    ret=DeQueue(Q,x);
    if(ret){
        printf("the front element is:%d",x);
    }
    return 0;
}

输出结果:
the front element is:1
进程已结束,退出代码为 0

3.5.2-2 Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。

#include 

//Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。

#define MaxSize 10
typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    int top;
}SqStack; //栈的结构体类型申明

typedef struct{
    ElemType data[MaxSize];
    int front,rear;
}SqQueue; //队列的结构体类型申明

//队列初始化
void InitQueue(SqQueue &Q){
    Q.front=Q.rear=0;
}


//队列入队:入队判队满
bool EnQueue(SqQueue &Q,ElemType x){
    if((Q.rear+1)%MaxSize==Q.front){
       printf("the queue is full\n");
       return false;
    }
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MaxSize;
    return true;
}

//队列出队:出队判队空
bool DeQueue(SqQueue &Q,ElemType &x){
    if(Q.rear==Q.front){
        printf("the queue is empty\n");
        return false;
    }
    x=Q.data[Q.front];
    Q.front=(Q.front+1)%MaxSize;
    return true;
}

//栈初始化
void InitStack(SqStack &S){
    S.top=-1;
}

//入栈:入栈判栈满
bool Push(SqStack &S,ElemType x){
    if(S.top==MaxSize-1){
        printf("the stack is full\n");
        return false;
    }
    S.data[++S.top]=x;
    return true;
}

//出栈:出栈判栈空
bool Pop(SqStack &S,ElemType &x){
    if(S.top==-1){
        printf("the stack is empty\n");
        return false;
    }
    x=S.data[S.top--];
    return true;
}

//算法思想:元素全部从队列出队,然后全部进栈,然后全部出栈,再全部入队
bool ReverseQueue(SqQueue &Q,SqStack &S){
    ElemType x;
    while(Q.front!=Q.rear){ //出队,入栈
        DeQueue(Q,x);
        Push(S,x);
    }
    while(S.top!=-1){ //出栈,入队
        Pop(S,x);
        EnQueue(Q,x);
    }
    return true;
}


int main() {
    SqQueue Q;
    InitQueue(Q);
    int i;
    while(i<9){
        EnQueue(Q,i+1);
        i++;
    }
    SqStack S;
    InitStack(S);
    ReverseQueue(Q,S);
    return 0;
}

3.2.5-4 请设计一个队列,要求满足:①初始时队列为空;②入队时,允许增加队列占用空间;③出队后,出队元素所占用的空间可重复使用,即整个队列所占用的空间只增不减;④入队操作和出队操作的时间复杂度始终保持为O(1)。请设计队列的存储结构,并实现入队和出队的基本操作。

#include 
#include

//请设计一个队列,要求满足:①初始时队列为空;②入队时,允许增加队列占用空间;
// ③出队后,出队元素所占用的空间可重复使用,即整个队列所占用的空间只增不减;
// ④入队操作和出队操作的时间复杂度始终保持为O(1)。请设计队列的存储结构,并实现入队和出队的基本操作。

//[分析]:队列允许增加占用空间且出队元素空间不自动释放,则只能使用链式存储。
// 又要求出队元素的空间可重复使用,则需要元素出队不断链,且要求入队和出队操作是O(1)复杂度,
// 考虑可使用不带头结点的单循环链表(带头结点时,front始终指向头结点,无法把出队的元素空间排在队尾后面)。
// 元素从队头出队后,即可排在队尾等待插入;front指针后移指向新的队头元素即可。
//需要考虑的是,如何判断队列空和满的问题?常规循环单链表判空的操作无法实现。
//借鉴循环队列,设置一个空闲结点,初始时,front和rear指针均指向空闲结点,且rear->next=front,则此时队列既是满,也是空;
// 即front指向当前元素,rear指向队尾元素的下一个元素(即下一个待插入结点)
//入队时,如队满,则在rear后面插入一个新的空闲结点,并使该结点指向front所指结点,
// 入队元素保存在rear所指的结点中,然后rear后移;如队不满,则直接在rear所指的结点插入元素,然后rear后移
//出队时,如队不空,则取front所指结点的元素,并使front=front->next.

typedef int ElemType;
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode;

typedef struct{
    LNode *front,*rear;
}LinkQueue;


//初始化队列
void InitQueue(LinkQueue &Q){
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->next=s;
    Q.front=Q.rear=s;
}

//判队空
bool IsEmpty(LinkQueue Q){
    if(Q.rear==Q.front){
        printf("the queue is empty\n");
        return true;
    }
    printf("the queue is not empty\n");
    return false;
}



//判队满
bool IsFull(LinkQueue Q){
    if(Q.rear->next==Q.front){
            printf("the queue is full\n");
            return true;
    }
    printf("the queue is not full\n");
    return false;
}


//入队
bool EnQueue(LinkQueue &Q,ElemType x){
    Q.rear->data=x;//将x值赋值给队尾指针所指结点
    if(IsFull(Q)){
        LNode *s=(LNode *)malloc(sizeof(LNode));//如队满,则开辟新的空闲结点
        s->next=Q.front;//新结点指向队头结点
        Q.rear->next=s;//然后将尾指针的next指针指向该结点
        Q.rear=s;//尾指针移动到该结点
    }else{
        Q.rear=Q.rear->next;//如队不满,rear指针后移指向下一个结点
    }
    return true;
}


//出队
bool DeQueue(LinkQueue &Q,ElemType &x){
    if(IsEmpty(Q)){
        return false;
    }else{
        x=Q.front->data;
        Q.front=Q.front->next;
    }
    return true;
}


int main() {
    LinkQueue Q;
    InitQueue(Q);
    printf("---------------------\n");
    printf("the initial queue is:\n");
    IsEmpty(Q);//初始时,既是队空,也是队满
    IsFull(Q);
    printf("--------------------\n");
    ElemType x;
    DeQueue(Q,x);//初始是空闲结点,不能出队
    EnQueue(Q,1);//初始时,即队满,入队需要开辟新的结点空间,并将元素插入前面一个结点中
    EnQueue(Q,2);//队满,开辟新空间,并将元素插入前面的结点
    DeQueue(Q,x);//队不空,出队
    DeQueue(Q,x);//队不空,出队
    DeQueue(Q,x);//出队队空,不能出队
    EnQueue(Q,6);//队不满,直接插入元素
    EnQueue(Q,7);//队不满,直接插入元素
    EnQueue(Q,8);//队满,开辟新的结点空间,并将元素插入前面一个结点中
    return 0;
}

输出结点:
---------------------
the initial queue is:
the queue is empty
the queue is full
--------------------
the queue is empty
the queue is full
the queue is full
the queue is not empty
the queue is not empty
the queue is empty
the queue is not full
the queue is not full
the queue is full

进程已结束,退出代码为 0

用栈实现中缀表达式的计算:

#include 
#include

//用栈实现中缀表达式的计算
//算法思想:
//① 初始化两个栈,操作数栈和运算符栈;
//②依次读取中缀表达式元素,如扫描到操作数,则压入操作数栈;
//③若扫描到运算符‘+-*/’或者界限符'()',则进行以下操作:
// a.如栈空,则将运算符压入运算符栈;
// b.如是左界限符‘(’,则也压入栈中;如是右界限符,则依次出栈运算符,同时将运算符加入后缀表达式,直到左界限符弹出栈;
// c.如是运算符’+-*/‘,则依次与栈顶元素进行比较,如栈顶元素的优先级大于等于现运算符,则将栈顶的运算符依次出栈并加入后缀表达式,最后再把当前运算符入栈。
//④ 每当从运算符栈弹出一个运算符,则从操作数栈弹出两个数字进行运算,并将运算结果压入操作数栈中;
//⑤后缀表达式扫描完毕后,如运算符栈不为空,则继续计算

#define MaxSize 20
typedef struct{
    int data[MaxSize];
    int top;
}DigitStack;

typedef struct{
    char data[MaxSize];
    int top;
}SignalStack;


//操作数入栈
bool PushDigit(DigitStack &S,int x){
    if(S.top==MaxSize-1){
        return false;
    }
    S.data[++S.top]=x;
    return true;
}

//操作数出栈
bool PopDigit(DigitStack &S,int &x){
    if(S.top==-1){
        return false;
    }
    x=S.data[S.top--];
    return true;
}


//运算符入栈
bool PushSignal(SignalStack &S,char x){
    if(S.top==MaxSize-1){
        return false;
    }
    S.data[++S.top]=x;
    return true;
}


//运算符出栈
bool PopSignal(SignalStack &S,char &x){
    if(S.top==-1){
        return false;
    }
    x=S.data[S.top--];
    return true;
}


//比较运算符优先级
int ComPri(char x){
    if(x=='+'||x=='-'){
        return 1;
    }else if(x=='*'||x=='/'){
        return 2;
    }else{ //指的是'('
        return 0;
    }
}


//操作数计算
int calculate(char s,int left,int right){ //left为左操作数,right为右操作数
    switch(s){
        case '+':return left+right;
        case '-':return left-right;
        case '*':return left*right;
        case '/':return left/right;
        default:return 9999;
    }
}


void CalExp(char str[],int length,int &result){ //result保存计算结果
    DigitStack ds;//操作数栈
    SignalStack ss;//运算符栈
    ds.top=-1;//操作数栈初始化
    ss.top=-1;//运算符栈初始化
    int left,right;//左操作数和右操作数
    int cal=0;//保存操作数阶段计算结果
    char stop;//保存栈顶的运算符
    for(int i=0;i='0'&&str[i]<='9'){ //如是操作数,则压入操作数栈
            int digit=0;
            while(str[i]>='0'&&str[i]<='9'){ //计算操作数
                digit=digit*10+(int)(str[i]-'0');
                i++;
            }
            PushDigit(ds,digit);
        }
        if(ss.top==-1||str[i]=='('){ //运算符栈空或者是左括号,则直接压入运算符栈
                PushSignal(ss,str[i]);
            }else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'){ //当前为运算符
                while(ComPri(ss.data[ss.top])>= ComPri(str[i])){ //将当前元素依次与栈顶元素比较,弹出所有优先级不低于当前元素的运算符
                    PopSignal(ss,stop);//运算符栈顶元素出栈
                    PopDigit(ds,right);//右操作数先出栈
                    PopDigit(ds,left);//左操作数后出栈
                    cal=calculate(stop,left,right);//计算新的操作数
                    PushDigit(ds,cal);//将操作数计算结果压入操作数栈
                }
                PushSignal(ss,str[i]);//将当前运算符压入栈中
            }else if(str[i]==')'){
                PopSignal(ss,stop);
                while(stop!='('){ //依次将运算符出栈并加入后缀表达式计算,直到左括号
                    PopDigit(ds,right);//右操作数先出栈
                    PopDigit(ds,left);//左操作数后出栈
                    cal=calculate(stop,left,right);//计算新的操作数
                    PushDigit(ds,cal);//将操作数计算结果压入操作数栈
                    PopSignal(ss,stop);
                }
            }
    }
    while(ss.top!=-1){ //如运算符栈不为空,则继续计算
        PopSignal(ss,stop);//运算符栈顶元素出栈
        PopDigit(ds,right);//右操作数先出栈
        PopDigit(ds,left);//左操作数后出栈
        cal=calculate(stop,left,right);//计算新的操作数
        PushDigit(ds,cal);//将操作数计算结果压入操作数栈
    }
    PopDigit(ds,result);
}



int main() {
    char str[20];
    int length;//统计字符串长度
    int result;//表达式计算结果
    printf("input expression:\n");
    gets(str);
    puts(str);
    length=strlen(str);//计算字符串长度,不包含结束符
    printf("length is:%d\n",length);
    CalExp(str,length,result);
    printf("the result is:%d\n",result);
    return 0;
}

输出结果:
input expression:
3-(5*2)+10*(6+2)
3-(5*2)+10*(6+2)
length is:16
the result is:73

进程已结束,退出代码为 0

3.3.6-1 栈在括号匹配中的应用

#include 

//栈在括号匹配中的应用
#define MaxSize 20
typedef char ElemType;
typedef struct{
    ElemType data[MaxSize];
    int top;
}SqStack;

//初始化栈
void InitStack(SqStack &S){
    S.top=-1;
}


//判断栈空
bool IsEmpty(SqStack S){
    if(S.top==-1){
        return true;
    }
    return false;
}

//入栈
bool Push(SqStack &S,ElemType x){
    if(S.top==MaxSize-1){
        return false;
    }
    S.data[++S.top]=x;
    return true;
}

//出栈
bool Pop(SqStack &S,ElemType &x){
    if(S.top==-1){
        return false;
    }
    x=S.data[S.top--];
    return true;
}


//括号匹配检查
//算法思想:初始设置一个空栈,依次读取括号,如是左括号,则依次入栈;
// 如是右括号,判断栈是否为空,如空,则不匹配;
// 如栈不空,则出栈并将出栈元素与右括号判断是否匹配,如匹配,继续读取括号;
//如括号读取完毕,此时栈不空,则不匹配。

bool BracketCheck(ElemType str[],int length){
    SqStack S;
    InitStack(S);
    for(int i=0;i

3.3.6-3 利用一个栈实现以下递归函数的非递归计算:
Pn(x)=1,n=0; Pn(x)=2x,n=2;Pn(x)=2xPn-1(x)-2(n-1)Pn-2(x),n>1.

#include 

#define MaxSize 20

//用递归算法实现函数
double FuncPn1(int n,double x){
    if(n<=1){
        return (n==0?1:2*x);
    }else{
       return 2*x* FuncPn1(n-1,x)-2*(n-1)* FuncPn1(n-2,x);
    }
}

//利用栈实现非递归计算
//算法思想:
//①设置一个栈,用于保存n和对应的Pn(x);
//②首先将n值,从n到2依次入栈(因为n=1和n=0对应的Pn(x)作为初始值已经给出);
//③计算Pn(x),先用P0和P1计算P2,再用P2和P1计算P3,以此类推。因此设置两个变量P1和P2记录此中间变量,初始时,P1=P0,P2=P1;
// 然后计算栈顶元素的值P3,并且P1=P2,P2=P3,栈顶元素出栈,再计算下一个栈顶元素的值,直到栈空。


double FuncPn2(int n,double x){
    typedef struct{
        int num; //n值
        double val;  //Pn(x)的值
    }SqStack;
    SqStack S[MaxSize]; //定义栈-结构体数组
    int top=-1;//结构体数组S的下标变量
    double p1=1,p2=2*x;//初始化中间变量的值
    for(int i=n;i>=2;i--){ //从n到2依次入栈
        S[++top].num=i;
    }
    while(top!=-1){ //栈不为空时,则依次计算
        S[top].val=2*x*p2-2*(S[top].num-1)*p1;//计算栈顶元素的值
        p1=p2;//中间变量p1更新为现在的p2值
        p2=S[top].val;//p2更新为栈顶元素的值
        top--;//栈顶元素出栈
    }
    if(n==0){ //如n值输入为0,则返回p1
        return p1;
    }
    return p2;//如n值输入为1,则直接返回p2;如n值输入为大于等于2,则为最后返回的栈顶元素值,即为p2
}



int main() {
    double count;
    count= FuncPn1(3,2);
    printf("count1=%5.2f\n",count);
    count= FuncPn2(3,2);
    printf("count2=%5.2f",count);
    return 0;
}

输出结果:
count1=40.00
count2=40.00
进程已结束,退出代码为 0

你可能感兴趣的:(数据结构,数据结构,c语言)