【数据结构与算法】栈和队列题解

🎬 博主名称键盘敲碎了雾霭
🔥 个人专栏 : 《C语言》《数据结构》

⛺️指尖敲代码,雾霭皆可破


文章目录

  • 一、有效的括号
    • [1.1 问题描述](#1.1 问题描述)
    • [1.2 解题思想](#1.2 解题思想)
    • [1.3 代码实现](#1.3 代码实现)
  • 二、用队列实现栈
    • [2.1 问题描述](#2.1 问题描述)
    • [2.2 解题思想](#2.2 解题思想)
    • [2.3 代码实现](#2.3 代码实现)
  • 三、用栈实现队列
    • [3.1 问题描述](#3.1 问题描述)
    • [3.2 解题实现](#3.2 解题实现)
    • [3.3 代码实现](#3.3 代码实现)
  • 四、设计循环队列
    • [4.1 问题描述](#4.1 问题描述)
    • [4.2 解题实现](#4.2 解题实现)
    • [4.3 代码实现](#4.3 代码实现)

一、有效的括号

1.1 问题描述

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

有效字符串需满足:

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

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

每个右括号都有一个对应的相同类型的左括号
原链接:20.有效的括号

1.2 解题思想

左括号用栈的结构装起来,右括号每次比较前从栈拿左括号(后进后出)

1.3 代码实现

c 复制代码
typedef char Datatype;
typedef struct STack
{
    Datatype*arr;
    int size;
    int capacity;
}ST;
void STInit(ST*pst)
{
    assert(pst);
    pst->arr=NULL;
    pst->size=pst->capacity=0;
}

void STPush(ST*pst,Datatype x)
{
    assert(pst);
    if(pst->size==pst->capacity)
    {
        int newcapacity=pst->capacity==0?4:pst->capacity*2;
        Datatype*ptr=(Datatype*)realloc(pst->arr,sizeof(Datatype)*newcapacity);
        if(ptr==NULL)
        {
            perror("realloc");
            return;
        }
        pst->arr=ptr;
        pst->capacity=newcapacity;
    }
    pst->arr[pst->size++]=x;
}
void STPop(ST*pst)
{
    assert(pst->size>0);
    assert(pst);
    pst->size--;
}
bool STEmpty(ST*pst)
{
    return pst->size==0;
}
Datatype STTop(ST*pst)
{
    assert(pst);
    assert(!STEmpty(pst));
    return pst->arr[pst->size-1];
}
int STSize(ST*pst)
{
    assert(pst);
    return pst->size;
}
void STDestroy(ST*pst)
{
    assert(pst);
    if(pst->arr)
    {
        free(pst->arr);
    }
    pst->size=pst->capacity=0;
}

bool isValid(char* s) 
{
    ST st;
    STInit(&st);
    while(*s)
    {
        if(*s=='{'||*s=='['||*s=='(')
        {
            STPush(&st,*s);
        }
        else
        {
            if(STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }
            Datatype tmp =STTop(&st);
            if((*s==']'&&tmp!='[')||(*s=='}'&&tmp!='{')||(*s==')'&&tmp!='('))
            {
                return false;
            }
            STPop(&st);
        }
        s++;
    }
    if(!STEmpty(&st))
    {
        STDestroy(&st);
        return false;
    }
    return true;
}

二、用队列实现栈

2.1 问题描述

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

2.2 解题思想

找头元素时,把元素导入空队列,增元素时,添加到非空队列

2.3 代码实现

c 复制代码
typedef int QDatatype;
typedef struct QueueNode
{
    QDatatype val;
    struct QueueNode*next;
}QNode;
typedef struct Queue
{
    QNode*phead;
    QNode*ptail;
    int size;
}Queue;
void QInit(Queue*q)
{
    assert(q);
    q->phead=q->ptail=NULL;
    q->size=0;
}
void QPush(Queue *q,QDatatype x)
{
    assert(q);
    QNode*newnode=(QNode*)malloc(sizeof(QNode));
    if(newnode==NULL)
    {
        perror("malloc");
        return;
    }
    newnode->next=NULL;
    newnode->val=x;
    if(q->phead==NULL)
    {
        q->phead=q->ptail=newnode;
    }
    else
    {
        q->ptail->next=newnode;
        q->ptail=newnode;
    }
    q->size++;
}
void QPop(Queue *q)
{
    assert(q);
    assert(q->size>0);
    if(q->phead->next==NULL)
    {
        free(q->phead);
        q->phead=q->ptail=NULL;
    }
    else
    {
        QNode*next = q->phead->next;
        free(q->phead);
        q->phead=next;
    }

    q->size--;
}
int QTop(Queue*q)
{
    assert(q);
    assert(q->phead);
    return q->phead->val;
}
int QBack(Queue*q)
{
    assert(q);
    assert(q->ptail);
    return q->ptail->val;
}
bool QEmpty(Queue *q)
{
    assert(q);
    return q->size==0;
}
int QSize(Queue*q)
{
    assert(q);
    return q->size;
}
void QDestroy(Queue *q)
{
    assert(q);

        while(q->phead)
        {
            QNode*next =q->phead->next;
            free(q->phead);
            q->phead=next;
        }
        q->ptail=q->phead=NULL;
}

typedef struct 
{
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() 
{
    MyStack *pst=(MyStack*)malloc(sizeof(MyStack));
    QInit(&pst->q1);
    QInit(&pst->q2);
    return pst;
}

void myStackPush(MyStack* obj, int x) 
{
    assert(obj);
    if(!QEmpty(&obj->q1))
    {
        QPush(&obj->q1,x);
    }
    else
    {
        QPush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) 
{
    Queue *empty=&obj->q1;
    Queue *nonempty=&obj->q2;
    if(QEmpty(&obj->q2))
    {
        empty=&obj->q2;
        nonempty=&obj->q1;
    }
    while(QSize(nonempty)>1)
    {
        QPush(empty,QTop(nonempty));
        QPop(nonempty);
    }
    QDatatype ret =QTop(nonempty);
    QPop(nonempty);
    return ret;
}

int myStackTop(MyStack* obj) 
{
    if(!QEmpty(&obj->q1))
    {
        return QBack(&obj->q1);
    }
    else
    {
       return  QBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    return (QEmpty(&obj->q1)&&QEmpty(&obj->q2));
}

void myStackFree(MyStack* obj) 
{
    QDestroy(&obj->q1);
    QDestroy(&obj->q2);
    free(obj);
}

三、用栈实现队列

3.1 问题描述

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

3.2 解题实现

建立两个栈,第一个栈一个只入栈,当另一个栈不为空,将第一个栈栈倒置到另一个栈

3.3 代码实现

c 复制代码
typedef int STDatatype;
typedef struct STack
{
    STDatatype*arr;
    int size;
    int capacity;
}STack;

void STInit(STack*pst)
{
    pst->arr=NULL;
    pst->size=pst->capacity=0;
}

void STPush(STack*pst,STDatatype x)
{
    if(pst->size==pst->capacity)
    {
        int newcapacity=pst->capacity==0?4:2*pst->capacity;
        pst->arr=(STDatatype*)realloc(pst->arr,sizeof(STDatatype)*newcapacity);
        pst->capacity=newcapacity;
    }
    pst->arr[pst->size++]=x;
}

void STPop(STack*pst)
{
    pst->size--;
}
int STTop(STack*pst)
{
    return pst->arr[pst->size-1];
} 
bool STEmpty(STack*pst)
{
    return pst->size==0;
}
void STDestroy(STack*pst)
{
    if(pst->arr)
    {
        free(pst->arr);
    }
    pst->size=pst->capacity=0;
}
typedef struct 
{
    STack pushst;
    STack popst;
} MyQueue;

int myQueuePeek(MyQueue* obj) ;
MyQueue* myQueueCreate() 
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

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



int myQueuePop(MyQueue* obj) 
{
    int ret = myQueuePeek(obj);
    STPop(&obj->popst);
    return ret;
}

int myQueuePeek(MyQueue* obj) 
{
    if(STEmpty(&obj->popst))
    {
        while(!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst,STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }

    int ret = STTop(&obj->popst);
    return ret;
}

bool myQueueEmpty(MyQueue* obj) 
{
    return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);    
}

void myQueueFree(MyQueue* obj) 
{
    STDestroy(&obj->pushst);
    STDestroy(&obj->popst);
    free(obj);
}

四、设计循环队列

4.1 问题描述

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

4.2 解题实现

注意head和tail的边界情况(取模运算)

4.3 代码实现

c 复制代码
typedef struct 
{
    int *arr;
    int head;
    int tail;
    int k;
} MyCircularQueue;

bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->arr=(int *)malloc(sizeof(int)*(k+1));
    obj->head=obj->tail=0;
    obj->k=k;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->arr[obj->tail++]=value;
    obj->tail%=(obj->k+1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->head++;
    obj->head%=obj->k+1;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->arr[obj->head];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->arr[((obj->tail-1)+(obj->k+1))%(obj->k+1)];  
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->head==obj->tail;    
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    if(((obj->tail+1)%(obj->k+1))==obj->head)
    {
        return true;
    }
    return false;
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->arr);
    free(obj);    
}
相关推荐
ShineWinsu1 小时前
对于C++:继承的解析—上
开发语言·数据结构·c++·算法·面试·笔试·继承
浅念-6 小时前
C++ 模板进阶
开发语言·数据结构·c++·经验分享·笔记·学习·模版
We་ct7 小时前
LeetCode 222. 完全二叉树的节点个数:两种解法详解(BFS + 二分查找优化)
数据结构·算法·leetcode·typescript
无限进步_8 小时前
21. 合并两个有序链表 - 题解与详细分析
c语言·开发语言·数据结构·git·链表·github·visual studio
wengqidaifeng9 小时前
数据结构与算法经典OJ题目详解(C语言):从数组到链表的进阶之路(上)
c语言·数据结构·链表
blackicexs9 小时前
第六周第一天
数据结构·算法
We་ct10 小时前
LeetCode 236. 二叉树的最近公共祖先:两种解法详解(递归+迭代)
前端·数据结构·算法·leetcode·typescript
历程里程碑11 小时前
普通数组---合并区间
java·大数据·数据结构·算法·leetcode·elasticsearch·搜索引擎
无忧.芙桃11 小时前
AVL树的实现
数据结构·c++