栈和队列专项练习

简介: 👩‍💻博客主页:[风起 风落](https://blog.csdn.net/qq_62939852?spm=1001.2101.3001.5343)的博客主页✨欢迎关注🖱点赞🎀收藏⭐留言✒👕参考网站:牛客网🎨你的收入跟你的不可替代成正比🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦💬给大家介绍一个求职刷题收割offer的地方👉[点击网站](https://www.nowcoder.com/link/pc_csdncpt_fqfl_c)

👩‍💻博客主页:风起 风落的博客主页

✨欢迎关注🖱点赞🎀收藏⭐留言✒

👕参考网站:牛客网

🎨你的收入跟你的不可替代成正比

🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦

💬给大家介绍一个求职刷题收割offer的地方👉点击网站

在这里插入图片描述

@TOC


一、20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。

左括号必须以正确的顺序闭合。

示例 1:

输入:s = "()"

输出:true

示例 2:

输入:s = "()[]{}"

输出:true

示例 3:

输入:s = "(]"

输出:false

示例 4:

输入:s = "([)]"

输出:false

示例 5:

输入:s = "{[]}"

输出:true

提示:

1 <= s.length <= 104

s 仅由括号 '()[]{}' 组成

typedef char datatype;
typedef struct stack
{
    datatype* a;
    int top;
    int capacity;
}ST;
void stackinit(ST* p);
void stackpush(ST* p,datatype x);
 datatype stacktop(ST* p);
void stackpop(ST* p);
int stacksize(ST* p);
bool stackempty(ST* p);
void stackdestroy(ST* p);
void stackinit(ST* p)//栈的初始化
{
    assert(p);
    p->a = NULL;
    p->top = 0;
    p->capacity = 0;
}
void stackpush(ST* p, datatype x)//入栈
{
    assert(p);
    if (p->top == p->capacity)
    {
        int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;
        datatype* tmp = (datatype*)realloc(p->a, sizeof(datatype)*newcapacity);
        if (tmp != NULL)
        {
            p->a = tmp;
            p->capacity = newcapacity;
        }
    }
    p->a[p->top] = x;
    p->top++;
}
void stackpop(ST* p)//移除栈顶元素
{
    assert(p);
    assert(p->top > 0);
    p->top--;
}
datatype  stacktop(ST* p)//出栈
{
    assert(p);
    assert(p->top>0);
    return p->a[p->top - 1];
}
bool  stackempty(ST* p)//是否为空
{
    return p->top == 0;
}
int stacksize(ST* p)//栈中元素个数
{
    assert(p);
    return p->top;
}
void stackdestroy(ST* p)//内存销毁
{
    assert(p);
    free(p->a);
    p->a = NULL;
    p->top = 0;
    p->capacity = 0;
}
bool isValid(char * s){
    ST p;
    stackinit(&p);
      while(*s)
      {
          if((*s=='(')||(*s=='{')||(*s=='['))
          {
             stackpush(&p,*s); 
             s++;
          }
          else
          {
              if(stackempty(&p))//当只有']'时,栈中没有数据存在  ,判断是否为空,
              {                 //为空则false
                  stackdestroy(&p);
                  return false;
              }
              datatype top=stacktop(&p);
              stackpop(&p);
              if((top=='[')&&(*s!=']')||(top=='{')&&(*s!='}')||(top=='(')&&(*s!=')'))
              {
                  stackdestroy(&p);
                  return false;
              }
              else
              {
                    s++;
              }
          }
      }
      bool ret=stackempty(&p);//当只有'['进入判断栈是否为空 若不为空则false
      stackdestroy(&p);
      return ret;
}

将左边的括号移入栈中,若碰到右括号 取出栈顶的元素,并将删除栈顶元素

比较 此时的栈顶元素是否与右括号匹配 ,若匹配则 s++,若不匹配就报错

    当只有'['输入时 ,循环直接出来了, 栈中还有元素存在,判断栈是否为空

若不为空则返回fasle

当只有']'输入时,栈中无元素存在,判断栈是否为空,若为空则返回fasle

二、225. 用队列实现栈

>请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
>注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
>示例:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

c

typedef int datatype;

typedef struct queuenode

{

   datatype data;

   struct queuenode* next;

}queuenode;

typedef struct queue

{

   queuenode* head;

   queuenode* tail;

}queue;

void queueinit(queue* p);

void queuedestroy(queue* p);

void queuepush(queue* p, datatype x);

void queuepop(queue* p);

datatype queuefront(queue* p);

datatype queueback(queue* p);

int queuesize(queue* p);

bool queueempty(queue* p);

void queueinit(queue* p)//初始化队列

{

   assert(p);

   p->head = NULL;

   p->tail = NULL;

}

void queuedestroy(queue* p)//内存销毁

{

   assert(p);

   queuenode* cur = p->head;

   while (cur != NULL)

   {

       queuenode* next = cur->next;

       free(cur);

       cur = next;

   }

   p->head = NULL;

   p->tail = NULL;

}

void queuepush(queue* p, datatype x)//入队列 (队尾入)

{

   assert(p);

   queuenode* newnode = (queuenode)malloc(sizeof(queuenode));     newnode->data = x;     newnode->next = NULL;     if (p->tail == NULL)     {         p->tail = newnode;         p->head = newnode;     }     else     {         p->tail->next = newnode;         p->tail = newnode;     } } void queuepop(queue p)//删除数据

{

   assert(p);

   assert(!queueempty(p));//断言队列是否为空

   queuenode* next = p->head->next;

   free(p->head);

   p->head = next;

   if (p->head == NULL)//当删除只剩下最后一个节点时 head与tail都指向,free(head) ,tail就变成了野指针

   {

       p->tail = NULL;

   }

}

datatype queuefront(queue* p)//取队头数据

{

   assert(p->head);

   assert(!queueempty(p));

   return p->head->data;

}

datatype queueback(queue* p)//取队尾数据

{

   assert(p->head);

   assert(!queueempty(p));

   return p->tail->data;

}

int queuesize(queue* p)//队的数量

{

   assert(p);

   int sum = 0;

   queuenode* cur = p->head;

   while (cur != NULL)

   {

       sum++;

       cur = cur->next;

   }

   return sum;

}

bool queueempty(queue* p)//判断队列是否为空

{

   assert(p);

   return p->head == NULL;

}

typedef struct {

queue q1;

queue q2;

} MyStack;

MyStack* myStackCreate() {//初始化

 MyStackobj=(MyStack)malloc(sizeof(MyStack));

 queueinit(&obj->q1);

 queueinit(&obj->q2);

 return obj;

}

void myStackPush(MyStack* obj, int x) {// 将元素 x 压入栈顶

  if(!queueempty(&obj->q1))

  {

      queuepush(&obj->q1,x);

  }

  else

  {

      queuepush(&obj->q2,x);

  }

}

int myStackPop(MyStack* obj) {//移除并返回栈顶元素

   queueempty=&obj->q1;     queuenoempty=&obj->q2;

   if(!queueempty(&obj->q1))

   {

       noempty=&obj->q1;

       empty=&obj->q2;

   }

   while(queuesize(noempty)>1)

   {

       queuepush(empty,queuefront(noempty));

       queuepop(noempty);

   }

   int top=queuefront(noempty);

   queuepop(noempty);

   return top;

}

int myStackTop(MyStack* obj) {// 返回栈顶元素

 if(!queueempty(&obj->q1))

 {

     return queueback(&obj->q1);

 }

 else

 {

     return queueback(&obj->q2);

 }

}

bool myStackEmpty(MyStack* obj) {//当两个队列都为空时

  return queueempty(&obj->q1)&&queueempty(&obj->q2);

}

void myStackFree(MyStack* obj) {

 queuedestroy(&obj->q1);

 queuedestroy(&obj->q2);

 free(obj);

}

/**

  • Your MyStack struct will be instantiated and called as such:
  • MyStack* obj = myStackCreate();
  • myStackPush(obj, x);
  • int param_2 = myStackPop(obj);
  • int param_3 = myStackTop(obj);
  • bool param_4 = myStackEmpty(obj);
  • myStackFree(obj);
    */
>主要思想为将数据传入不为空的队列中,想要找到栈顶元素时就将n-1个元素都转移到空的队列中,
>返回不为空的队列的最后一个元素即栈顶元素并删除元素,若此时再返回栈顶元素即队列最后一个元素
>![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/711360b6a1c946c3b5f366fe87ce62f3.png)
# 三、232. 用栈实现队列
>请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
>实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
>示例 1:
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
>提示:
1 <= x <= 9
最多调用 100 次 push、pop、peek 和 empty
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

c

typedef int datatype;

typedef struct stack

{

   datatype* a;

   int top;

   int capacity;

}ST;

void stackinit(ST* p);

void stackpush(ST* p,datatype x);

datatype stacktop(ST* p);

void stackpop(ST* p);

int stacksize(ST* p);

bool stackempty(ST* p);

void stackdestroy(ST* p);

void stackinit(ST* p)//栈的初始化

{

   assert(p);

   p->a = NULL;

   p->top = 0;

   p->capacity = 0;

}

void stackpush(ST* p, datatype x)//入栈

{

   assert(p);

   if (p->top == p->capacity)

   {

       int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;

       datatype* tmp = (datatype)realloc(p->a, sizeof(datatype)newcapacity);

       if (tmp != NULL)

       {

           p->a = tmp;

           p->capacity = newcapacity;

       }

   }

   p->a[p->top] = x;

   p->top++;

}

void stackpop(ST* p)//移除栈顶元素

{

   assert(p);

   assert(p->top > 0);

   p->top--;

}

datatype  stacktop(ST* p)//出栈

{

   assert(p);

   assert(p->top>0);

   return p->a[p->top - 1];

}

bool  stackempty(ST* p)//是否为空

{

   return p->top == 0;

}

int stacksize(ST* p)//栈中元素个数

{

   assert(p);

   return p->top;

}

void stackdestroy(ST* p)//内存销毁

{

   assert(p);

   free(p->a);

   p->a = NULL;

   p->top = 0;

   p->capacity = 0;

}

typedef struct {

 ST pushST;

 ST popST;

} MyQueue;

MyQueue* myQueueCreate() {

  MyQueueobj=(MyQueue)malloc(sizeof(MyQueue));

  stackinit( &obj->pushST);

  stackinit(&obj->popST);

  return obj;

}

void myQueuePush(MyQueue* obj, int x) {

   stackpush(&obj->pushST,x);//将数据都传入pushST中

}

int myQueuePop(MyQueue* obj) {//判断popST是否为空 若为空则将pushST的数据传入popST中,

                               //若不为空则直接返回队列开头

  if(stackempty(&obj->popST))

  {

      while(stacksize(&obj->pushST))

      {

          stackpush(&obj->popST,stacktop(&obj->pushST));

          stackpop(&obj->pushST);

      }

  }

  int front=stacktop(&obj->popST);

  stackpop(&obj->popST);

  return front;

}

int myQueuePeek(MyQueue* obj) {//返回队列开头的元素

  if(stackempty(&obj->popST))

  {

      while(stacksize(&obj->pushST))

      {

          stackpush(&obj->popST,stacktop(&obj->pushST));

          stackpop(&obj->pushST);

      }

  }

  return stacktop(&obj->popST);

}

bool myQueueEmpty(MyQueue* obj) {//两个栈都为空才为空

   return stackempty(&obj->pushST)&&stackempty(&obj->popST);

}

void myQueueFree(MyQueue* obj) {

    stackdestroy(&obj->pushST);

    stackdestroy(&obj->popST);

    free(obj);

}

/**

  • Your MyQueue struct will be instantiated and called as such:
  • MyQueue* obj = myQueueCreate();
  • myQueuePush(obj, x);
  • int param_2 = myQueuePop(obj);
  • int param_3 = myQueuePeek(obj);
  • bool param_4 = myQueueEmpty(obj);
  • myQueueFree(obj);
    */
>本题与上个类似题不同的是,如果设置一个为空的栈,一个不为空的栈,则会发现将数据传给空的栈中时,因为栈时先进后出,所以顺序回颠倒。
>所以这道题采用一个只管入数据的pushST,一个只管出数据的popST
>![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/37ccb6a064384eb298061a15d3c2b886.png)
# 四、622. 设计循环队列
>设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
>示例:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

c

typedef struct {

  int* a;

  int  front;

  int  tail;

  int  k;

} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {

      MyCircularQueueobj=( MyCircularQueue)malloc(sizeof( MyCircularQueue));

      obj->a=(int)malloc(sizeof(int)(k+1));

      obj->front =0;

      obj->tail=0;

      obj->k=k;

      return obj;

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj);

bool myCircularQueueIsFull(MyCircularQueue* obj);

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {

  if(myCircularQueueIsFull(obj))

  {

      return false;

  }

  obj->a[obj->tail]=value;

  obj->tail++;

  obj->tail%=(obj->k+1);

  return true;

}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {

     if(myCircularQueueIsEmpty(obj))

     {

         return false;

     }

     obj->front++;

     obj->front%=(obj->k+1);

     return true;

}

int myCircularQueueFront(MyCircularQueue* obj) {

   if(myCircularQueueIsEmpty(obj))

   {

       return -1;

   }

   return obj->a[obj->front];

}

int myCircularQueueRear(MyCircularQueue* obj) {

   if(myCircularQueueIsEmpty(obj))

   {

       return -1;

   }

   if(obj->tail==0)

   {

       return obj->a[obj->k];

   }

   else

   {

       return obj->a[obj->tail-1];

   }

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {

   return obj->front==obj->tail;

}

bool myCircularQueueIsFull(MyCircularQueue* obj) {

      return (obj->tail+1)%(obj->k+1)==obj->front;

}

void myCircularQueueFree(MyCircularQueue* obj) {

   free(obj->a);

   free(obj);

}

/**

  • Your MyCircularQueue struct will be instantiated and called as such:
  • MyCircularQueue* obj = myCircularQueueCreate(k);
  • bool param_1 = myCircularQueueEnQueue(obj, value);
  • bool param_2 = myCircularQueueDeQueue(obj);
  • int param_3 = myCircularQueueFront(obj);
  • int param_4 = myCircularQueueRear(obj);
  • bool param_5 = myCircularQueueIsEmpty(obj);
  • bool param_6 = myCircularQueueIsFull(obj);
  • myCircularQueueFree(obj);
    */
    ```

本题采用用数组实现:

分为两种情况:

为空时:

若phead==tail时 为空

在这里插入图片描述为满时:此时需要考虑空间的问题, 1.若只取k个空间需要进入数据时,tail被赋值,tail向后移一个,当最后一块空间被赋值时,tail回到下标为0的数组中,此时tail ==front与判断空的条件相同 ,所以不成立。 在这里插入图片描述 2.若取k+1个空间

正常情况:

tail+1==front

在这里插入图片描述 特殊情况下 在这里插入图片描述   在这里插入图片描述 在这里插入图片描述   在这里插入图片描述
目录
相关文章
|
22天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
109 9
|
13天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
21 1
|
16天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
19天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
21天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
47 4
|
25天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
数据结构(栈与列队)
数据结构(栈与列队)
20 1
|
1月前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
71 1
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
17 0
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
33 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器