OJ题目【栈和队列】

逆向-落叶 2024-08-16 13:05:02 阅读 96

目录

有效的括号

有效的括号【代码】

用队列实现栈

用队列实现栈【代码】

用栈实现队列

用栈实现队列【代码】

设计循环队列


有效的括号

https://leetcode.cn/problems/valid-parentheses/submissions/551394950/

思路:把左括号放到栈里,取出来栈顶和右括号匹配,匹配上了就出栈,然后在取出栈顶和下一个右括号匹配,一直匹配下去,


创建一个栈用来存放左括号,然后把字符串的首地址s给ps,让ps遍历到\0。


来看看循环里面,

第一步:判断把左括号全部放进栈里。

第二步:判断栈里是不是空,是空就没必要匹配了,没有左括号,直接返回false。

第三步:走到第三步,说明左括号全部放进栈里了,然后取出栈顶给ch,

然后左括号右括号进行匹配,匹配成功就出栈,匹配不成功就销毁,然后返回false。


解决只有一个左括号的情况。

布尔判断栈里是不是空,是空把true给tab,不是空返回false给tab。

销毁空间后,返回tab。


有效的括号【代码】

<code>typedef char data;

typedef struct stack

{

data* arr;

int koj;//空间大小

int top;//栈顶

}SL;

//初始化

void csh(SL* r)

{

r->;arr = NULL;

r->koj = r->top = 0;

}

//入栈

void push(SL* r, data x)

{

//判断空间够不够

if (r->koj == r->top)

{

int koj1 = r->koj == 0 ? 4 : 2 * r->koj;

SL* tab = (SL*)realloc(r->arr, koj1 * sizeof(SL));

if (tab == NULL)

{

perror("realloc");

exit(1);

}

r->arr = tab;

r->koj = koj1;

}

r->arr[r->top] = x;

r->top++;

}

bool buer(SL* r)

{

assert(r);

return r->top == 0;

}

//出栈

void pop(SL* r)

{

assert(r);

assert(!buer(r));

--r->top;

}

//取栈顶

data qzd(SL* r)

{

assert(r);

assert(!buer(r));

return r->arr[r->top-1];

}

//取有效个数

data size(SL* r)

{

assert(r);

return r->top;

}

//销毁

void xiaoh(SL* r)

{

assert(r);

if (r->arr != NULL)

{

free(r->arr);

}

r->arr = NULL;

r->koj = r->top = 0;

}

//上面是栈需要的函数

//下面是实现代码

bool isValid(char* s) {

//创建一个栈

SL add;

//把s给ps

char*ps=s;

//循环让ps往后走

while(*ps!='\0')

{

//判断把左括号放进栈里

if(*ps=='(' || *ps=='[' || *ps=='{')

{

push(&add,*ps);

}

else

{

//判断栈顶是不是空,是空返回false。

if(buer(&add))

{

return false;

}

//取出左括号放进ch来

char ch = qzd(&add);

//判断左括号和右括号匹不匹配

if((*ps==')'&&ch=='(')

||( *ps==']'&&ch=='[')

|| (*ps=='}'&& ch=='{'))

{

//匹配出栈

pop(&add);

}

else

{//不匹配直接销毁返回false

xiaoh(&add);

return false;

}

}

ps++;

}

//布尔判断栈里是不是为空,是空把true赋值给tab。

char tab = buer(&add) == true;

xiaoh(&add);

return tab;

}


用队列实现栈

https://leetcode.cn/problems/implement-stack-using-queues/description/

实现前先导入队列的函数

思路:创建2个队列

入栈不为空的队列Q1。

出栈的话把Q1的size-1的数据1和2插入Q2的队列,我们就可以把3出栈了。

https://leetcode.cn/problems/implement-stack-using-queues/


第一步:先创建2个队列来实现栈。

第二步:创建ps指向栈,然后初始化这2个队列。


入栈,为不为空的队列,入数据到队列。

if用布尔判断Q1队列是不是空,是空往Q2队列入数据,调用入队列函数。


第一步:把Q1给空队列,把Q2给不为空的队列。

第二步:判断Q1如果不为空,2个交换,把Q1给buko,把Q2给ko。

第三步:循环把有效个数-1的数据,给到为空的队列。

取出队头数据给tab,然后入队到空队列,再把不为空的队列出队。

第四步:把队列的最后一个数据,保存到pop,然后出队列,返回pop。


布尔判断,找不为空的队列,取出队尾数据,返回队尾。


布尔判断2个队列是不是空,2个都为真返回true,有1个或2个为假,返回false。


销毁直接调用销毁队列的函数就行了,然后把obj销毁,把obj置为NULL。


用队列实现栈【代码】

<code>typedef int data;

typedef struct queuedata//单链表

{

data arr;//存放的数据

struct queuedata* p;//指向下一个节点

}queuedata;

typedef struct Queue

{

queuedata* to; //队头——单链表的 头节点

queuedata* wei;//队尾——单链表的 尾节点

int size; //有效个数

}Queue;

//初始化

void csh(Queue* r)

{

assert(r);

r->;to = r->wei = NULL;

r->size = 0;

}

//入队尾

void dui_wei(Queue* r,data x)

{

assert(r);

//申请单链表空间

queuedata* tab = (queuedata*)malloc(sizeof(queuedata));

if (tab == NULL)

{

perror("malloc");

exit(1);

}

//把x赋值给新申请空间的arr

tab->arr = x;

tab->p = NULL;

//入队

//判断队尾是不是空

if (r->wei == NULL)

{

//是空,队头队尾指向新申请的空间

r->to = r->wei = tab;

}

else//不是空

{

//队尾p指向新申请的空间

r->wei->p = tab;

//队尾走到新申请的空间

r->wei = r->wei->p;

}

//有效个数加1

r->size++;

}

//布尔类型

bool buer(Queue* r)

{

assert(r);

return r->to == NULL;

}

//出队,头

void dui_to(Queue* r)

{

assert(r);

//布尔类型,!把真变假,把假变真

assert(!buer(r));

//判断队头等于队尾,就说明只有一个节点

if (r->to == r->wei)

{

//直接释放空间

free(r->to);

//把队头和队尾置为空

r->to = r->wei = NULL;

}

else

{

//把队头的下一个节点给tab

queuedata* tab = r->to->p;

//释放当前队头节点

free(r->to);

//把tab节点给队头

r->to = tab;

}

//有效个数减1

--r->size;

}

//取队头数据

data qto(Queue* r)

{

assert(r);

assert(!buer(r));

return r->to->arr;

}

//取尾

data qwei(Queue* r)

{

assert(r);

assert(!buer(r));

return r->wei->arr;

}

//有效个数

data size(Queue* r)

{

assert(r);

return r->size;

}

//销毁

void xiaoh(Queue* r)

{

assert(r);

//assert(!buer(r));

//把队头给tab

queuedata* tab = r->to;

//循环销毁单链表

while (tab != NULL)

{

//add保存头节点的下一个节点

queuedata* add = tab->p;

//释放头节点

free(tab);

//把add给tab

tab = add;

}

//把队头和队尾置为空

r->to = r->wei = NULL;

//有效个数赋值为0

r->size = 0;

}

//上面是队列的函数

/

//下面是实现代码

typedef struct {

//创建2个队列来实现栈

Queue Q1;

Queue Q2;

} MyStack;

//栈初始化

MyStack* myStackCreate()

{

//创建ps指向栈

MyStack*ps=(MyStack*)malloc(sizeof(MyStack));

//初始化这2个队列

csh(&ps->Q1);

csh(&ps->Q2);

return ps;

}

//入栈

void myStackPush(MyStack* obj, int x) {

//往不为空的队列插入数据

if(!buer(&obj->Q1))

{

dui_wei(&obj->Q1, x);

}

else

{

dui_wei(&obj->Q2, x);

}

}

//出栈

int myStackPop(MyStack* obj) {

//空

Queue* ko = &obj->Q1;

//不为空

Queue* buko = &obj->Q2;

//找不为空的队列

if(!buer(&obj->Q1))

{

buko = &obj -> Q1;

ko = &obj -> Q2;

}

//把有数据的队列中size-1个数据导入到空队列中

while(size(buko) > 1)

{

//取队头给tab

int tab = qto(buko);

//把tab的数据给 ko空队列

dui_wei(ko , tab);

//出队,头

dui_to(buko);

}

//不为空的队列还剩下一个数据,给pop

int pop = qto(buko);

//最后一个数据出栈

dui_to(buko);

//返回pop

return pop;

}

//取栈顶元素

int myStackTop(MyStack* obj) {

//找不为空的队列,取出队尾数据

if(!buer(&obj->Q1))

{

return qwei(&obj->Q1);

}

else

{

return qwei(&obj->Q2);

}

}

bool myStackEmpty(MyStack* obj) {

//用布尔判断2个队列是不是空

return buer(&obj->Q1) && buer(&obj->Q2);

}

//销毁

void myStackFree(MyStack* obj) {

//直接调用销毁队列的函数就行了

xiaoh(&obj->Q1);

xiaoh(&obj->Q2);

//把我们申请的ps销毁,obj就是ps,返回了ps然后obj接收。

free(obj);

//置为空

obj=NULL;

}

/**

* 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);

*/

用栈实现队列

https://leetcode.cn/problems/implement-queue-using-stacks/description/

实现前先导入栈的函数


思路:用2个栈Q1,Q2,

入队列:往Q1导入数值,

出队列(头):判断Q2是不是空,是就循环取出Q1栈顶,导入到Q2,Q2再出栈,出的就是队头了,对了还要先保存队头,再返回队头的数据。

取队头数据:判断Q2是不是空,不是空就说明数据已经导入到Q2了,直接取栈顶。

myQueueEmpty:判断队列是不是空。

销毁:调用销毁函数,销毁2个栈,再把申请的obj空间释放,然后置为空。


第一步:创建2个栈。

第二步:创建ps空间指向Q1和Q2,

然后初始化这2个栈,返回ps。


直接调用,入栈函数,为Q1导入数据就行了。


判断Q2栈是不是空,是空的话循环把Q1的全部数值,导入到Q2,

取出Q2栈顶给tab,Q2出栈,返回tab。


判断Q2栈是不是空,是空的话循环把Q1的全部数值,导入到Q2

返回Q2栈顶的元素就行了。


判断队列是不是空,是空返回false,不是空返回true。


把Q1和Q2的栈销毁,然后销毁obj,把obj置为空。


用栈实现队列【代码】

<code>typedef int data;

typedef struct stack

{

data* arr;//存放数值

int koj; //空间

int top; //栈顶

}stack;

//初始化

void stack_csh(SL* r)

{

assert(r);

r->;arr = NULL;

r->koj = r->top = 0;

}

//入栈

void stack_push(stack* r, data x)

{

assert(r);

//空间大小等于栈顶,就说明空间不够

if (r->koj == r->top)

{

int koj1 = r->koj == 0 ? 4 : 2 * r->koj;

stack* tab = (stack*)realloc(r->arr, sizeof(stack));

if (tab == NULL)

{

perror("realloc");

exit(1);

}

//把新申请的空间给r

r->arr = tab;

r->koj = koj1;

}

//空间够直接入栈

r->arr[r->top] = x;

r->top++;

}

//布尔类型

bool buer(stack* r)

{

assert(r);

return r->top == 0;

}

//出栈

void stack_pop(stack* r)

{

assert(r);

//布尔类型

assert(!buer(r));

r->top--;

}

//取出栈顶

data stack_top(stack* r)

{

assert(r);

assert(!buer(r));

return r->arr[r->top - 1];

}

//有效个数

data stack_size(stack* r)

{

assert(r);

return r->top;

}

//销毁

void xiaoh(stack* r)

{

assert(r);

if (r->arr != NULL)

{

free(r->arr);

}

r->arr = NULL;

r->koj = r->top = 0;

}

//上面是栈的函数

/

//下面是实现代码

typedef struct {

//创建2个栈

stack Q1;

stack Q2;

} MyQueue;

//初始化

MyQueue* myQueueCreate() {

//创建指针指向Q1和Q2

MyQueue* ps = (MyQueue*)malloc(sizeof(MyQueue));

//初始化2个栈

stack_csh(&ps->Q1);

stack_csh(&ps->Q2);

//返回ps

return ps;

}

//入栈(入队列)

void myQueuePush(MyQueue* obj, int x) {

//调用入栈函数,为Q1入栈

stack_push(&obj->Q1 , x);

}

//出栈(出队列,头)

int myQueuePop(MyQueue* obj) {

//判断Q2是不是空,不是空说明Q2栈里有数据

if( buer(&obj->Q2) )

{

//是空,循环取出Q1的数值,导入Q2栈里

while(!buer(&obj->Q1))

{

//入栈到Q2 取出Q1栈顶

stack_push(&obj->Q2,stack_top(&obj->Q1));

//Q1出栈

stack_pop(&obj->Q1);

}

}

//取出Q2的栈顶给tab(取队头)

int tab = stack_top(&obj->Q2);

//Q2出栈

stack_pop(&obj->Q2);

return tab;

}

//取栈顶(队头)

int myQueuePeek(MyQueue* obj) {

//判断Q2是不是空,不是空说明Q2栈里有数据

if( buer(&obj->Q2) )

{

//是空,循环取出Q1的数值,导入Q2栈里

while(!buer(&obj->Q1))

{

//入栈到Q2 取出Q1栈顶

stack_push(&obj->Q2,stack_top(&obj->Q1));

//Q1出栈

stack_pop(&obj->Q1);

}

}

//返回Q2的栈顶(返回队头)

return stack_top(&obj->Q2);

}

bool myQueueEmpty(MyQueue* obj) {

//判断这2个栈是不是都为空(判断队列是不是空)

return buer(&obj->Q1) && buer(&obj->Q2);

}

void myQueueFree(MyQueue* obj) {

//销毁

xiaoh(&obj->Q1);

xiaoh(&obj->Q2);

//也把obj销毁

free(obj);

obj=NULL;

}

/**

* 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);

*/


设计循环队列

https://leetcode.cn/problems/design-circular-queue/description/

这个队列底层使用数组,比较好实现。


结构体的参数,数组,头,尾,空间大小。


申请ps的一个结构体,

给arr申请一个数值的空间,我们申请的数值空间必须多一块空间,方便5%5等于0。

初始化:把头尾初始化为0,空间大小初始化为k,k就是4。


第一步:先判断队列是不是满了,满了直接返回false,没有满插入数据。

第二步:为arr数组wei下标位置插入数据,然后++,参考【1%5=1, 2%5=2 ,3%5=3, 4%5=4, 5%5=0】。

当wei走到下标为5,5%5=0,所以就会回到0,返回true。


第一步:判断队列是不是空,是空直接返回false。

第二步:头直接++就好了,1%5=1, 2%5=2 ,3%5=3, 4%5=4, 5%5=0

当to走到下标为5,5%5=0,所以就会回到0,返回true。


先判断是不是空,不是空返回头,是空返回-1。


第一步:判断队列是不是空。

第二步:把wei-1的数据赋值tab,为什么是wei-1呢?

上面这一张图,我们可以看到插入数据后就++了,所以我们取队尾,wei-1。

第三步:判断尾下标是不是0,这里是一种特殊情况0-1=-1,-1没有下标,

我们直接把空间大小给tab就是下标为4这个元素了。

返回arr下标为tab的数值。



设计循环队列代码

<code>typedef struct {

int *arr;

int to;//头

int wei;//尾

int kojdax;//空间大小

} MyCircularQueue;

//初始化

MyCircularQueue* myCircularQueueCreate(int k) {

//申请空间

MyCircularQueue* ps = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));

// 4 * 5 = 20,就是5个空间

ps->;arr = (int*)malloc(sizeof(int) * (k + 1));

//初始化

ps->to = ps->wei = 0;

ps->kojdax = k;

return ps;

}

bool myCircularQueueIsFull(MyCircularQueue* obj) {

//判断队列是不是满了,等于头就说明满了

return (obj->wei+1) % (obj->kojdax+1) == obj->to;

}

//入队列

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {

//队列满了不能插入数据

if(myCircularQueueIsFull(obj))

{

return false;

}

//在wei位置插入数据,然后++

obj->arr[obj->wei++] = value;

//5 % 5 = 0,rear走到5下标的时候回到下标为0的位置。

obj->wei %= obj->kojdax + 1;

return true;

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {

//等于就说明队列是空

return obj->to == obj->wei;

}

//出队列

bool myCircularQueueDeQueue(MyCircularQueue* obj) {

//队列为空

if(myCircularQueueIsEmpty(obj))

{

return false;

}

//队列不为空

//头往后走就行

obj->to++;

//会越界所以:5 % 5 = 0,to走到5下标的时候回到下标为0的位置。

obj->to %= obj->kojdax + 1;

return true;

}

//取队头

int myCircularQueueFront(MyCircularQueue* obj) {

//判断队列是不是空

if(myCircularQueueIsEmpty(obj))

{

return -1;

}

//返回头

return obj->arr[obj->to];

}

//取队尾

int myCircularQueueRear(MyCircularQueue* obj) {

//判断队列是不是空

if(myCircularQueueIsEmpty(obj))

{

return -1;

}

//把wei-1的数据给tab

int tab = obj->wei - 1;

//尾等于下标0

if(obj->wei == 0)

{

//把有效个数4给tab

tab = obj -> kojdax;

}

//返回tab

return obj->arr[tab];

}

//销毁

void myCircularQueueFree(MyCircularQueue* obj) {

free(obj->arr);

free(obj);

obj=NULL;

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。