[LeetCode]栈,队列相关题目(C语言实现)

2023-11-15

LeetCode20. 有效的括号

题目

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

要求

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

思路
用栈实现

  1. 如果是左括号, 直接将左括号入栈
  2. 如果是右括号, 如果此时栈为空, 返回 false; 将栈顶元素弹出栈, 如果栈顶元素不是对应的左括号, 返回 false; 如果栈顶元素是对应左括号, 出栈
  3. 遍历完字符串, 判断此时栈是否为空. 为空返回 true; 不为空返回 false

代码实现

#define N 10000
bool isValid(char * s)
{
    char stack[N] = {0,};   //创建栈数组
    int top = 0;            //top指向栈顶元素的后一个空间
    char topVal = 0;        //用来存放栈顶元素

    while (*s)
    {
        //如果是左括号
        if (*s == '{' || *s == '(' || *s == '[')
        {
            //入栈
            stack[top] = *s;
            top++;
        }
        //如果是右括号
        else
        {
            //如果此时栈为空, 直接返回false
            if (top == 0)
            {
                return false;
            }

            topVal = stack[top - 1];    //得到栈顶元素
            top--;  //栈顶元素出栈

            //如果右括号不是其对应的左括号, 直接返回false
            if ((*s == ']' && topVal != '[')
            || (*s == ')' && topVal != '(')
            || (*s == '}' && topVal != '{'))
            {
                return false;
            }
        }
        s++;
    }

    //如果遍历完字符串, 栈仍为空, 则返回true
    if (top == 0)
        return true;
    else
        return false;
}

LeetCode225. 用队列实现栈

题目

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

OJ链接

要求

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false

思路

  1. 使用两个队列,一个队列no_empty_que存放已经存放的元素,另一个队列empty_que常空
  2. 当要压栈的时候,将元素压入no_empty_que
  3. 当要出栈的时候,将no_empty_que中除队尾元素全部存入empty_que,将队尾元素移出

实例
在这里插入图片描述

代码实现

typedef int QDataType;

// 链式结构表示队列
typedef struct QListNode
{
  struct QListNode* next;
  QDataType data;
}QNode;

// 队列的结构
typedef struct Queue
{
  QNode* front;    //指向队列头
  QNode* rear;     //指向队列尾
  int size;        //记录队列的元素个数
}Queue;

// 初始化队列
void QueueInit(Queue* q)
{
  assert(q);  //确保q合法

  q->front = q->rear = NULL;  //将头和为置为 NULL 
  q->size = 0;
}

// 判断队列是否为空, 如果为空返回非0, 非空返回0
int QueueEmpty(Queue* q)
{
  assert(q);  //确保q合法

  if (q->size == 0)
  {
    return 1;
  }
  else 
  {
    return 0;
  }
}

// 队尾入队列
void QueuePush(Queue* q, QDataType x)
{
  assert(q);  //确保q合法

  //创建新结点
  QNode* newNode = (QNode*)malloc(sizeof(QNode));
  newNode->data = x;
  newNode->next = NULL;

  //入队列
  if (QueueEmpty(q))
  {
    //如果队列为空,直接赋值
    q->front = q->rear = newNode;
  }
  else 
  {
    //如果队列不为空,直接尾插
    q->rear->next = newNode;
    q->rear = newNode;
  }

  q->size++;
}

// 队头出队列
void QueuePop(Queue* q)
{
  assert(q);  //确保q合法
  assert(!QueueEmpty(q)); //确保队列不为空

  if (q->size == 1)
  {
    //如果只有一个元素,头删的同时还要将尾指针置空
    free(q->front);
    q->front = q->rear = NULL;
  }
  else 
  {
    //如果不止一个元素,则只头删
    QNode* nextNode = q->front->next;
    free(q->front);
    q->front = nextNode;
  }

  q->size--;
}

// 获取头部元素
QDataType QueueFront(Queue* q)
{
  assert(q);  //确保q合法
  assert(!QueueEmpty(q)); //确保队列不为空

  return q->front->data;
}

// 获取尾部元素
QDataType QueueBack(Queue* q)
{
  assert(q);  //确保q合法
  assert(!QueueEmpty(q)); //确保队列不为空

  return q->rear->data;
}

// 获取队列元素个数
int QueueSize(Queue* q)
{
  assert(q);  //确保q合法

  return q->size;
}



// 销毁队列
void QueueDestroy(Queue* q)
{
  assert(q);

  while(!QueueEmpty(q))
  {
    QNode* nextNode = q->front->next;
    free(q->front);
    q->front = nextNode;
  }

  q->front = q->rear = NULL;
  q->size = 0;
}

//用两个队列构成一个栈
typedef struct 
{
    Queue queue1;
    Queue queue2;
} MyStack;


MyStack* myStackCreate() 
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&pst->queue1);
    QueueInit(&pst->queue2);

    return pst;
}

void myStackPush(MyStack* obj, int x) 
{
    if (!QueueEmpty(&obj->queue1))
    {
        QueuePush(&obj->queue1, x);
    }
    else
    {
        QueuePush(&obj->queue2, x);
    }
}



int myStackPop(MyStack* obj) 
{
    Queue* no_empty_que = &obj->queue1;
    Queue* empty_que = &obj->queue2;

    if (!QueueEmpty(&obj->queue2))
    {
        no_empty_que = &obj->queue2;
        empty_que = &obj->queue1;
    }

    //弹出有元素的队列直至只剩一个元素
    while (QueueSize(no_empty_que) > 1)
    {
        QueuePush(empty_que, QueueFront(no_empty_que));
        QueuePop(no_empty_que);
    }

    int pop = QueueFront(no_empty_que);
    QueuePop(no_empty_que);
    return pop;
}

int myStackTop(MyStack* obj) 
{
    if (!QueueEmpty(&obj->queue1))
    {
      return QueueBack(&obj->queue1);
    }
    else
    {
      return QueueBack(&obj->queue2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    return QueueEmpty(&obj->queue1) && QueueEmpty(&obj->queue2);
}

void myStackFree(MyStack* obj) 
{
    QueueInit(&obj->queue1);
    QueueInit(&obj->queue2);
    free(obj);
}

LeetCode232. 用栈实现队列

题目

你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):OJ链接

要求

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路

  1. 使用两个栈,一个专门负责压入数据push_stack,另一个专门负责弹出数据pop_stack
  2. 当push数据,直接将数据压入push_stack
  3. 当pop数据,如果pop_stack为空,先将push_stack中的数据压入,pop_stack,再接将pop_stack的栈顶弹出

实例
在这里插入图片描述

代码实现

typedef int STDataType;

typedef struct Stack
{
  STDataType* a;  //指向栈空间
  int top;        //栈顶
  int capacity;   //容量
}Stack;

// 初始化栈
void StackInit(Stack* ps)
{
  assert(ps);
  
  ps->a = NULL;     
  ps->top = 0;
  ps->capacity = 0;
}

//入栈
void StackPush(Stack* ps, STDataType data)
{
  assert(ps);       //确保ps合法

  //如果容量不够则扩容
  if (ps->capacity == ps->top)
  {
    int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;   //定义新的容量
    STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);  //开辟新的空间
    if (tmp == NULL)
    {
      perror("malloc error");
      exit(-1);
    }
    else 
    {
      ps->a = tmp;
      ps->capacity = newCapacity;
    }
  }

  //将数据入栈
  ps->a[ps->top] = data;
  ps->top++;
}

// 出栈
void StackPop(Stack* ps)
{
  assert(ps); //确保ps合法

  assert(!StackEmpty(ps));  //确保栈不为空
  ps->top--;

}

// 检测栈是否为空, 如果为空返回非零结果, 如果不为空返回 0
int StackEmpty(Stack* ps)
{
  assert(ps); //确保ps合法
  
  if (ps->top > 0)
  {
    return 0;
  }
  else 
  {
    return 1;
  }
}

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
  assert(ps);   //确保ps合法
  assert(!StackEmpty(ps));  //确保栈不为空

  return ps->a[ps->top - 1];
}

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
  assert(ps);   //确保ps合法
  return ps->top;
}

// 销毁栈
void StackDestroy(Stack* ps)
{
  assert(ps); //确保ps合法

  free(ps->a);
  ps->a = NULL;
  ps->capacity = 0;
  ps->top = 0;
}

typedef struct 
{
    Stack push_stack;
    Stack pop_stack;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* que = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&que->push_stack);
    StackInit(&que->pop_stack);

    return que;
}

void myQueuePush(MyQueue* obj, int x) 
{
    StackPush(&obj->push_stack, x);
}

int myQueuePop(MyQueue* obj) 
{
    int pop = myQueuePeek(obj);
    StackPop(&obj->pop_stack);

    return pop;
}

int myQueuePeek(MyQueue* obj) 
{
    //如果pop_stack是空的话,将push_stack的所有元素入pop_stack
    if (StackEmpty(&obj->pop_stack))
    {
        while (!StackEmpty(&obj->push_stack))
        {
          StackPush(&obj->pop_stack, StackTop(&obj->push_stack));
          StackPop(&obj->push_stack);
        }
    }
    //如果pop_stack不是空,直接取栈顶元素
    int peek = StackTop(&obj->pop_stack);

    return peek;
}

bool myQueueEmpty(MyQueue* obj) 
{
    return StackEmpty(&obj->push_stack) && StackEmpty(&obj->pop_stack);
}

void myQueueFree(MyQueue* obj) 
{
    StackDestroy(&obj->push_stack);
    StackDestroy(&obj->pop_stack);
    free(obj);
}

LeetCode622. 设计循环队列

题目

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。OJ链接

要求

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

思路

  1. 为了确保方便判断空和满情况,将循环队列的空间比设定长度加1
  2. 入队列和出队列相关frontrear不是简单的加一或减一
  3. rear指向队尾下一个空间,front指向队头元素

代码实现

typedef struct 
{
    int* a;     //存放队列元素
    int front;  //指向队头元素
    int rear;   //指向队尾下一个元素
    int k;      //循环队列的大小
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    cq->a = (int*)malloc(sizeof(int) * (k + 1));
    cq->front = cq->rear = 0;
    cq->k = k;
    
    return cq;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->front == obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    //如果满了,插入失败
    if (myCircularQueueIsFull(obj))
    {
        return false;
    }

    //如果不满,进行插入,注意rear的大小
    obj->a[obj->rear] = value;
    obj->rear = (obj->rear + 1) % (obj->k + 1);

    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    //如果没有元素,删除失败
    if (myCircularQueueIsEmpty(obj))
    {
        return false;
    }

    //直接修改front的值即可
    obj->front = (obj->front + 1) % (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;
    }
    return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[LeetCode]栈,队列相关题目(C语言实现) 的相关文章

  • MessageBoxA的用法

    一 函数原型 int fastcall MessageBox const char Text const char Caption int Flags 0x0 Flags表示对话框的按钮组合 取值有 MessageBox Flags def
  • 虚拟地址内存空间

    bss段详解 详细讲解
  • 一个简单的HttpClient使用案例

    HttpClient 是什么 HttpClient 是Apache Jakarta Common 下的子项目 可以用来提供高效的 最新的 功能丰富的支持 HTTP 协议的客户端编程工具包 并且它支持 HTTP 协议最新的版本和建议 该如何使

随机推荐

  • Web3-js的学习(5)-实现合约事件监听

    合约事件监听 latest 监听最新出块事件 pending 监听发布未进块事件 代码很简单 var Web3 require web3 var web3 new Web3 new Web3 providers HttpProvider h
  • 解决在Intellij IDEA中无法创建Servlet类的问题/New中没有Servlet类/创建不了Servlet类

    新手在学习Servlet相关知识的时候 一些课程往往会告知新手去使用IDEA自带的模板来创建Servlet 这样减少了注解等麻烦 降低了工作量 然而 如下图所示 很多人发现在自己的new一栏不存在Servlet类 如下图 网上的解决办法很多
  • 服务 -web服务器及ssh

    web服务器 文件共享 nfs samba 一般用于局域网中 ftp http 一般用于公网 tcp 80 httpd apache 1 完全开源 2 跨平台 3 支持多种编程语言 4 采用模块化的设计 5 安全稳定 IE www taob
  • 笔记/samba搭建

    1 安装 yum y install samba 2 配置 vim etc samba smb conf global 安全模式 user shared domain security user 认证模式 passdb backend td
  • autosar宏定义搜集

    1 AUTOSAR 长函数声明 2 教你如何阅读Autosar代码 1 概述 3 把AUTOSAR函数以及变量等定义的宏用脚本展开以提高可读性 4 Specification of Compiler Abstraction autosar
  • C语言满天星加月亮

    import java awt Color import java awt Graphics import javax swing JFrame import javax swing JPanel public class Stars pu
  • C++关键字 noexcept

    1 关键字noexcept 从C 11开始 我们能看到很多代码当中都有关键字noexcept 比如下面就是std initializer list的默认构造函数 其中使用了noexcept constexpr initializer lis
  • 使用JAVA反射的利与弊

    b color olive size large 在Java的20周年的纪念日的日子里 让我们来重新温习下Java里面的高级知识 Java肯定希望大家了解她 要不然你跟她天天相濡以沫了这么长时间 让她知道你竟然不了解她 不在乎她 那么她该有
  • wsus服务器搭建自动更新

    WSUS服务器搭建 第一次写博客还有点小激动 没有啥过硬的技术手段 简单记录一下日常操作 整一个Windows 2012 Server镜像文件 简单说一下为啥我找的是win 2012 Server吧 微软好像发布了个停止对Windows S
  • SearchView详细使用

    Android SearchView详细使用 布局
  • 在Fedora16中安装Qt

    首先 在http www trolltech com download上下载linux下的qt源文件 我下载时最新版是 qt everywhere opensource src 4 7 4 tar gz 将该文件放到某个目录下 进行解压缩
  • conda常用命令汇总

    conda常用命令汇总 1 创建一个虚拟环境 conda create name pytorch gpu python 3 8 创建一个名为pytorch gpu 可自定义 的虚拟环境 3 8指的是所安装python版本 2 进入一个已经存
  • 【Linux】进程控制1-进程创建、进程终止

    文章目录 进程创建 fork函数 用户空间 内核空间 写实拷贝 fork创建子进程时的一些特性 守护进程 进程终止 正常终止 异常终止 exit和 exit的区别 缓冲方式 进程创建 fork函数 调用fork函数让正在运行的进程创建出来一
  • python出现__init__() got an unexpected keyword argument ‘size‘错误解决!!!

    代码运行出现 init got an unexpected keyword argument size 错误 根据官方文档 将size改为vector size
  • 【git】error: failed to push some refs to ‘https://github.com/biluko/ZJGSU-Exams-in-master-two.git‘

    我在提交代码的时候 遇到了下面的错误 To https github com biluko ZJGSU Exams in master two git rejected master gt master non fast forward e
  • webpack5从入门到精通

    前言 webpack是什么 摘自官网的一段话 webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具 当 webpack 处理应用程序时 它会在内部从一个或多个入口点构建一个 依赖图 dependency gra
  • IME SoftInputWindow窗口添加

    IME SoftInputWindow窗口添加 1 时序图 2 InputMethodService onCreate 3 Dialog添加到WMS android12 release1 1 时序图 输入法应用继承InputMethodSe
  • matplotlib绘制图表,设置刻度标签、最大最小刻度、字体大小,label位置、刻度轴箭头等

    matplotlib绘制图表 设置刻度标签 最大最小刻度 字体大小 label位置 刻度轴箭头等 1 效果图 2 源码 2 1 仅使用普通轴ax fontdict 源码 2 2 使用mpl设置全局字体 ax fontdict源码 写这篇博客
  • VUE知识(三)计算属性、监听属性、动画

    文章目录 一 计算属性 一 计算属性 computed 1 目标 2 语法 3 特点 4 注意 二 计算属性 缓存 1 目标 2 使用场景 3 优势 三 计算属性 完整写法 1 目标 2 语法 4 使用场景 二 监听属性 一 监听属性 wa
  • [LeetCode]栈,队列相关题目(C语言实现)

    文章目录 LeetCode20 有效的括号 LeetCode225 用队列实现栈 LeetCode232 用栈实现队列 LeetCode622 设计循环队列 LeetCode20 有效的括号 题目 给定一个只包括 的字符串 s 判断字符串是