数据结构第八章:栈与队列习题

一.题目一:括号匹配问题

题目介绍

给定一个只包括{ (和) }的字符串s,判断字符串是否有效?

有效字符需要满足:左括号必须与相应的右括号闭合。左右括号必须以正确的顺序闭合。

示例

s=()---------输出:true

s=()\[\]{}-------输出:true

s=(]-----------输出:false

思路展示

该题目需要用到栈的知识,因为栈的特性是后进先出,让左括号进行入栈,遇到右括号开始判断,如果匹配则继续判断;不匹配则输出结果。

代码展示

cpp 复制代码
void StackInit(ST* ps)    //栈区的初始化
{
  assert(ps);
  ps->a=(STDataType *)malloc(sizeof(STDataType)*4);
  ps->capacity=4;
  ps->top=0;
}

void StackDestory(ST *ps)    //栈区的销毁
{
  assert(ps);
  free(ps->a);
  ps->a=NULL;
  ps->top=ps->capacity=0;
}

void StackPush(ST *ps,STDataType x)    //栈区的插入
{
  assert(ps);
  if(ps->top==ps->capacity)
  {
    STDataType *tmp=(STDataType *)realloc(ps->a,ps->capacity*2*sizeof(STDataType));
    if(tmp==NULL)
    {
      printf("realloc fail!");
      exit(-1);
    }
    else 
    {
      ps->a=tmp;
      ps->capacity*=2;
    }
  }
  ps->a[ps->top]=x;
  ps->top++;
}

void StackPop(ST *ps)    //栈区的删除
{
  assert(ps);
  assert(ps->top>0);
  ps->top--;
}

STDataType StackTop(ST *ps)//获取栈顶部的元素
{
  assert(ps);
  assert(ps->top>0);
  return ps->a[ps->top-1];
}

int StackSize(ST *ps)    //获取栈的大小
{
  assert(ps);
  return ps->top;
}

bool StackEmpty(ST* ps)    //判断栈区是否为空
{
  assert(ps);
  return ps->top==0;
}

bool isValid (char *s)//括号匹配函数
{
    ST st;    //创建一个栈
    StackInit(&st);    //对栈进行初始化
    while(*s!='\0')    //参数不为\0时,进去循环,进行进一步的括号匹配判断
    {
        switch(*s)

        {
            case '(':
            case '[':
            case '{':    //如果为左括号则调用插入函数,将左括号插入在栈内,等待进一步的判断
            {
                StackPush(&st,*s)
                ++s;
                break;
            }
            case ')':
            case ']':
            case '}':    //如果为右括号,则取出栈顶元素与此时的右括号进行比对,如果对应则进行下一步判断。否则输出匹配失败的信息。
            {
                if(StackEmpty(&st))
                {
                    StackDestory(&st);
                    return false;
                }
                char top=StackTop(&st);
                StackPop(&st);
                else
                {
                    ++s;
                }
                break;
            }
        } 
    
    }

    bool ret=StackEmpty(&st);    //如果栈是空的说明括号不匹配,反之括号检查完毕,为匹配。
    StackDestory(&st);    //检查括号匹配之后,需要对栈进行销毁。
    return ret;    
}

上述代码的具体解释:因为我们学习初阶数据结构的语言基础为C语言,C语言不可以调用库,所以需要我们将栈的相关代码尽数拷贝到所写代码前面。

下面详细讲解一下我们最后一个函数:括号匹配函数。此函数运用到了栈的后进先出的基本特性。括号匹配问题化简之后就是,出现第一个右括号时,与上一个左括号进行比对。以此类推。当每个括号都比过一次,则可以得到匹配的结果。当然,如果中途出现括号不匹配的情况可以直接结束判断,直接输出false。

题目二:用队列实现栈

题目介绍

请你仅使用两个队列实现一个具有后进先出特性的栈结构

思路展示

队列的特性是先进先出,栈的特性是后进先出。可以根据两者的特性进行进阶的变化,下面将画图展示该变化。

代码展示

cpp 复制代码
void QueueInit(Queue *pq)    //队列的初始化
{
  assert(pq);
  pq->head=pq->tail=NULL;
}

void QueueDestory(Queue *pq)    //队列的销毁
{
  assert(pq);
  QNode* cur=pq->head;
  while(cur)
  {
    QNode* next=cur->next;
    free(cur);
    cur=next;
  }
  pq->head=pq->tail=NULL;
}

void QueuePush(Queue* pq,QDataType x)    //队列的插入
{
  assert(pq);
  QNode* newnode=(QNode*)malloc(sizeof(QNode));
  if(newnode==NULL)
  {
    printf("malloc fail");
    exit(-1);
  }
  newnode->data=x;
  newnode->next=NULL;
  if(pq->tail==NULL)
  {
    pq->head=pq->tail=newnode;
  }
  else
  {
    pq->tail->next=newnode;
    pq->tail=newnode;
  }
}

void QueuePop(Queue* pq)    //队列的删除
{
  assert(pq);
  assert(pq->head);
  if(pq->head->next==NULL)
  {
    free(pq->head)
    pq->head=pq->tail=NULL;
  }
  else
  {
    QNode* next=pq->head->next;
    free(pq->head);
    pq->head=next;
  }
}

QDataType QueueFront(Queue* pq)    //获取队头元素
{
  assert(pq);
  assert(pq->head);
  return pq->head->data;
}

QDataType QueueBack(Queue *pq)    //获取队尾元素
{
  assert(pq);
  assert(pq->head);
  return pq->tail->data;
}

int QueueSize(Queue* pq)    //获取队列的大小
{
  assert(pq);
  int size=0;
  QNode* cur=pq->head;
  while(cur)
  {
    ++size;
    cur=cur->next;
  }
  return size;
}

bool QueueEmpty(Queue* pq)    //判断队列是否为空
{
  assert(pq);
  return pq->head==NULL;
}


typedef struct    //有两个队列的结构体
{
  Queue q1;
  Queue q2;
} Mystack;

MystackCreat()    //栈的初始化
{
  Mystack *ps =(Mystack *)malloc(sizeof(Mystack));
  if(ps==NULL)
  {
    printf("malloc fail!");
    exit(-1);
  }
  QueueInit(&ps->q1);
  QueueInit(&ps->q2);
  return ps; 
}

void myStackPush(Mystack *obj,int x)    //栈的插入数据
{
  if(!QUEUEmpty(&obj->q1))
    QueuePush(&obj->q1,x);
  else 
    QueuePush(&obj->q2,x);
}

int mystackPop(MYstack *obj)    //队列的倒数据
{
  Queue *emptyQ = &obj->q1;
  Queue *nonemptyQ = &obj->q2;
  if(!QueueEmpty(&obj->q1))
  {
    emptyQ = &obj->q2;
    emptyQ = &obj->q1;
  }
  while(QueueSize(nonemptyQ)>1)
  {
    QueuePush(emptyQ,QueueFront(nonemptyQ));
    QueuePop(nonemptyQ);
  }
  int top = QueueFront(nonemptyQ);
  QueuePop(nonemptyQ);
  return top;
}

int mystack(Mystack *obj)    //返回栈元素
{
  if(!QUEUEmpty(&obj->q1))
    QueueBack(&obj->q1);
  else 
    QueueBack(&obj->q2);
}

bool mystackEmpty(Mystack *obj)    //判断栈是否为空
{
  return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void mystackFree(Mystack *obj)    //释放栈空间
{
  QueueDestory(&obj->q1);
  QueueDestory(&obj->q2);
  free(obj);
}

上述代码的具体解释:在栈的初始化函数中,需要将结构体内的成员变量进行初始化,(将两个队列进行相应的初始化);栈插入数据函数,需要将非空队列的末尾元素插入。所以需要将非空队列的元素悉数挪动到空队列中,剩余的最后一个元素插入栈中;栈的插入需要队列间不停的倒腾数据,所以直接写出新函数,用于队列数据间的倒腾过程。倒腾数据需要将非空队列的元素(除去最后一个元素以外)都置于空队列中;返回栈的元素实际上是返回非空队列的队尾元素,所以在返回栈元素的函数中直接调用返回队列尾部元素的函数即可;判断栈是否为空的函数,只需要判断两队列是否为空即可;释放栈的空间函数,需要先释放掉队列对应的链表,最后再释放掉栈指针。

题目三:用栈实现队列

题目介绍

请你仅使用两个栈实现一个具有先进先出特性的队列结构

思路展示

因为队列的特性是先进先出,栈的特性是后进先出。所以需要将栈进行一次数据的颠倒即可插入队列当中,因为思路和题目二一致,所以仅仅给出图片解释:

相关推荐
by2099912 小时前
哈希表——快速找到数据:冲突、删除与扩容的实现
数据结构·c++·哈希算法·散列表
Code_Solitude12 小时前
c语言:关于qsoet函数知识点
c语言·数据结构·算法
Pniubi13 小时前
快速排序(力扣基础)(递归)
java·数据结构·算法
inrichtt1 天前
第八课时:SPI总线揭秘:四线全双工通信的奥
c语言·数据结构·stm32·单片机·嵌入式硬件
HPtiger1 天前
数据结构——选择排序
数据结构·算法·排序算法
丑梨数据1 天前
信创环境里跑文档工具:格式兼容与本地合规的几个坑
数据结构·人工智能·算法·决策树·排序算法
烂蜻蜓1 天前
Pandas入门教程(四):Series数据结构——创建、索引与常用方法
数据结构·pandas
CS创新实验室1 天前
一棵树怎么做到“自平衡还不太费力“?——红黑树的旋转与染色
数据结构·算法·红黑树·408·计算机考研
Logic1011 天前
C语言/数据结构位运算题解:异或XOR找出被挑选一次的果子编号——只出现一次的数字
c语言·数据结构·算法·数组·位运算·时间复杂度·空间复杂度
从小白到软工1 天前
4-3 项目-学生成绩管理系统(上)
c语言·开发语言·数据结构·经验分享·ai编程