王道课后习题总结(第二部分 栈和队列)

第二部分栈和队列

2.1 栈

  1. 设单链表的表头指针为L,结点结构由data和next两个域组成,其中data域为字符型。试设计算法判断该链表的全部n个字符是否中心对称。例如xyx,xyyc都是中心对称。
//算法思想:使用栈来判断链表中的数据是否中心对称。让链表的前一半元素依次进栈。在处理链表的后一半元素时,当访问到链表的一个元素后,就从栈中弹出一个元素,两个元素比较,若相等,则将链表中的下一个元素与栈中再弹出的元素比较,直至链表到尾。这时若栈是空栈,则得出链表中心对称的结论;否则,当链表中的一个元素与栈中弹出元素不等时,结论为链表非中心对称,结束算法的执行。

int dc(LinkList L,int n)
{
    int i;
    char s[n/n];
    LNode *p=L->next;
    for(i=0;i<n/2;i++)
    {
        s[i]=p->data;
        p=p->next;
    }
    i--;                                    //恢复最后的i值
    
    if(n%2==1)                              //如果n为奇数,后移过中心结点
        p=p->next;
    
    while(p!=NULL&&s[i]==p->data)           //检测是否中心对称
    {
        i--;                                //i充当栈顶指针
        p=p->data; 
    }
    if(i==-1)                               //栈为空栈
        return 1;                    
    else
        return 0;
        
}
  1. 设有两个栈s1、s2都采用顺序栈方式,并共享一个存储区[0,…,maxsize-1],为了尽量利用空间,减少溢出的可能,课采用栈顶相向,迎面增长的存储方式。试设计s1、s2有关入栈和出栈的操作算法。
//定义结构体
/*
算法思想:两个栈共享向量空间,将两个栈的栈底设在向量两端,初始时,s1栈顶指针为-1,s2栈顶指针为maxSize。两个栈顶相向、迎面增长,栈顶指针指向栈顶元素。
*/

typedef struct{
    int stack[maxsize];              //栈空间
    int top[2];                      //top为两个栈顶指针
}stk;

stk s;
//入栈操作
/*
s1为通常意义下的栈,而s2栈入栈操作时,其栈顶指针左移(减1),退栈时,栈顶指针右移(加1)
*/

int push(int i,int x)
{
    if(i<0||i>1)
    {
        printf("栈号输入不对");
        exit(0);
    }
    
    if(s.top[1]-s.top[0]==1)
    {
        printf("栈已满\n");
        return 0;
    }
    
    switch(i)
    {
        case 0: s.stack[++s.top[0]]=x;return 1;break;
        case 1: s.stack[--top[1]]=x;return 1;     
    }
}
//退栈操作

int pop(int i)
{
    if(i<0||i>1)
    {
        printf("栈已满\n");
        return 0;
    }
    
    switch(i)
    {
        case 0:
           if(s.top[0]==-1)
           {
               printf("栈空\n");
               return -1;
           }
            else
                return s.stack[s.top[0]--];
        case 1:
            if(s.top[1]==maxsize)
            {
                printf("栈空\n");
                return -1;
            }
            else
                return s.stack[s.top[1]++];
    }//Switch
}

2.2 队列

  1. 将循环队列所有的元素都能够得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分对头指针front和队尾指针rear相同时的队列状态是“空”还是“满”。
/*
算法思想:进队:tag=1;出队:tag=0;
因为只有入队才能导致队满,只有出队才能导致队空

对空条件:Q.front==Q.rear&&Q.tag==0
队满条件:Q.front==Q.rear&&Q.tag==1
进队操作:Q.data[Q.rear]=x;Q.rear=(Q.rear+1)%maxSize;Q.tag=1;
出队操作:x=Q.dara[Q.front];Q.front=(Q.front+1)%maxSize;Q.tag=0;
*/
//入队操作

int EnQueue(SqQueue &Q,int x)
{
    if(Q.front==Q.rear&&Q.tag==1)
        return 0;
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%maxSize;
    Q.tag=1;
    return 1;
}
//出队操作

int DeQueue(SqQueue &Q,int x)
{
    if(Q.front==Q.rear&&Q.tag==0)
        return 0;
    x=Q.dara[Q.front];
    Q.front=(Q.front+1)%maxSize;
    Q.tag=0;
    return 1;
}
  1. 将队列中元素逆置
/*
算法思想:一般逆置都是采用的栈,来从中逆置
我们先将队列中元素放入栈中,再从栈中取出来,放入队列中
*/

void Inverser(Stack S,Queue Q)
{
    while(!QueueEmpty(Q))
    {
        x=DeQueue(Q);
        Push(S,x);
    }
    
    while(!StackEmpty(S))
    {
        Pop(S,x);
        EnQueue(Q,x);
    }
}

2.3 栈和队列的应用

  1. 假设一个算术表达式中包含圆括号,方括号和花括号3种类型的括号,编写一个算法来判断表达式中的括号是否配对,以字符“\0”作为算术表达式的结束符。
bool BraacketsCheck(char *str)
{
    InitStack(S);
    int i=0;
    while(str[i]!='\0')
    {
        switch(Str[i])
        {
                //左括号入栈
            case '(': Push(S,'(');break;
            case '[': Push(S,'[');break;
            case '{': Push(S,'{');break;
            //遇到右括号,检测栈顶
            case ')': Pop(S,e);
                if(e!='(') return false;
            break;
            case ']': Pop(S,e);
                if(e!='[') return false;
            break;
            case '}': Pop(S,e);
                if(e!='{') return false;
            break;
        }//swith
        i++;
    }
    if(!IsEmpty(S))
    {
        printf("括号不匹配!");
        return false;
    }
    else
    {
        printf("括号匹配!");
        return true;
    }
}
  1. 利用栈实现以下递归函数的非递归计算:

P n ( x ) = { 1 , n = 0 2 x , n = 1 2 x P n − 1 ( x ) − 2 ( n − 1 ) P n − 2 ( x ) , n > 1 P_n\left( x \right) =\begin{cases} 1, &&n=0\\ 2x, &&n=1\\ 2xP_{n-1}\left( x \right) -2\left( n-1 \right) P_{n-2}\left( x \right) , &&n>1\\ \end{cases} Pn(x)=1,2x,2xPn1(x)2(n1)Pn2(x),n=0n=1n>1

/*
算法思想:设置一个栈用于保存n和对应的Pn(x)值,栈中相邻元素的Pn(x)有题中关系。然后边出栈边计算Pn(x),栈空后该值就计算出来了。
*/

double p(int n, double x)
{
    if (n == 0)
        return 1;
    if (n == 1)
        return 2 * x;
    if (n > 1)
    {
        InitStack(S);
        double x1 = 1, x2 = 2 * x;
        int i = 2;
        Push(S, x1);
        Push(S, x2);
        while (i <= n)
        {
            x2 = Pop(S, top);
            x1 = Pop(S, top);
            x1 = 2 * x * x2 + 2 * (i - 1) * x1;
            Push(S, x2);
            Push(S, x1);
            i++;
        }
        return Push(S, top);
    }
}
  1. 某汽车轮渡口,过江渡船每次能载10辆车过江,过江车辆分为客车类货车类,上渡船有如下规定:同类车先到先上船;客车先于货车上船,且每上4辆客车,才允许放上1辆货车;若待客车不足4辆,则以货车代替;若无货车等待,允许客车都上船。试设计一个算法模拟渡口管理。
/*
算法思想:
          1、“同类车先到先上船”————队列,一个队列负责一种车
          2、每次上限是10,也就是4辆客车+1辆货车,4辆客车+1辆货车
          3、最后两句话其实就是“没有客车的话,货车可以替代客车;没有货车的话客车可以替代货车”
          4、写两个函数,用于上客车和货车,每一个内部再进行判断是否够用
*/

Queue q;      //过江渡船载渡队列
Queue q1;     //客车队列
Queue q2;     //货车队列

void manager()
{
    int i=0,j=0;
    while(j<10)
    {
        if(!QueueEmpty(q1)&&i<4)                     //客车队列不空,且未上足四辆
        {
            DeQueue(q1,x);
            EnQueue(q,x);
            i++;
            j++;
        }
        else if(i==4&&!QueueEmpty(q2))              //客车已经上足四辆
        {
            DeQueue(q2,x);
            EnQueue(q,x);
            j++;
            i=0;
        }
        else
        {
            while(j<10&&i<4&&!QueueEmpty(q2))       //其它情况
            {
                DeQueue(q2,x);
                EnQueue(q,x);
                i++;
                j++;
            }
            i=0;
        }
        if(QueueEmpty(q1)&&QueueEmpty(q2))
            j=11;
    }
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值