栈和队列代码实现及OJ

目录

栈的实现

1.Stack.h文件

2.Stack.c文件

队列的实现

1.Queue.h文件

2.Queue.c文件

栈和队列OJ

1.有效的括号

 理解题目:

解题思路:

2.用队列实现栈

解题思路: 

3.用栈实现队列

 解题思路:


栈的实现

1.Stack.h文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

//定义栈的结构
typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top; //指向栈顶的位置,也表示有效元素个数
	int capacity;//栈的容量
}ST;

//初始化栈
void StackInit(ST* ps);

//入栈——栈顶
void StackPush(ST* ps, STDataType x);

//判断栈是否为空
bool StackEmpty(ST* ps);

//出栈——栈顶
void StackPop(ST* ps);

//取栈顶元素
STDataType StackTop(ST* ps);

//获取栈中有效元素个数
int StackSize(ST* ps);

//栈的销毁
void StackDestroy(ST* ps);

2.Stack.c文件

#include"Stack.h"

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

//入栈——栈顶
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//判断空间是否足够
	if (ps->top == ps->capacity)
	{
		//增容
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	ps->arr[ps->top++] = x;
}

//判断栈是否为空
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
	//如果return后面的表达式正确
	//则返回ture,即栈为空
}

//出栈——栈顶
void StackPop(ST* ps)
{
	assert(!StackEmpty(ps));//栈不为空才能继续出栈操作
	ps->top--;
}

//取栈顶元素  (!=出栈,并没有减少有效元素个数)
STDataType StackTop(ST* ps)
{
	assert(!StackEmpty(ps));
	return ps->arr[ps->top - 1];
}

//获取栈中有效元素个数
int StackSize(ST* ps)
{
	return ps->top;
}

//栈的销毁
void StackDestroy(ST* ps)
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

队列的实现

1.Queue.h文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;
//队列结点的结构
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;

//队列的结构
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
}Queue;


//队列的初始化
void QueueInit(Queue* pq);

//入队——队尾
void QueuePush(Queue* pq, QDataType x);

//队列判空
bool QueueEmpty(Queue* pq);

//出队
void QueuePop(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);

//取队尾数据
QDataType QueueBack(Queue* pq);

//队列有效个数
int QueueSize(Queue* pq);

//销毁队列
void QueueDestroy(Queue* pq);

2.Queue.c文件

#include"Queue.h"

//队列初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
}

//入队——队尾
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	//申请空间
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	//队列为空
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	//非空
	else {
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
}

//队列判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}

//出队——队头
void QueuePop(Queue* pq)
{
	assert(!QueueEmpty(pq));
	//只有一个结点,phead和ptail都要置空,否则ptail变野指针
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else {
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
}

//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

//队列有效个数
int QueueSize(Queue* pq)
{
	QueueNode* pcur = pq->phead;
	int size = 0;
	while (pcur)
	{
		size++;
		pcur = pcur->next;
	}
	return size;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur;
	pcur = pq->phead;
	while (pcur != NULL)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
}

栈和队列OJ

1.有效的括号

20. 有效的括号 - 力扣(LeetCode)

 理解题目:

根据题目中满足有效字符串的三个条件,得知每个类型的左括号必须有相同类型的右括号按照正确的顺序闭合,可以比喻成消消乐,如实例1,左右小括号对应消除后什么都没有了,示例1满足;实例2也是一样的道理,从左到右小、中、大括号依次消除后没有剩余,示例2满足;同理,示例3括号不匹配则“消不掉”,不满足;实例4从内部的中括号开始消除,消除完后外层的小括号也可以对应消除,最后也没有剩余多余的括号,满足题意。

解题思路:

思路概括:运用数据结构——栈,遍历字符串,若是左括号则入栈,如果是右括号,则与栈顶的左括号匹配,如果匹配成功,栈顶的左括号出栈,更换新的栈顶,字符串也继续向后遍历,进行新一轮的比较;如果匹配不成功,也就是“消不掉”,那就无法成为有效字符串,直接返回false;如果遍历到右括号时发现栈内为空,那也不可能形成有效字符串,返回false;最后遍历完字符串后,还得判断栈内是否为空(左括号是否被完全匹配消除),如果为空则返回true,反之则返回false。具体代码如下:(为了避免内容重复冗余,实现栈功能的代码不再呈现在下面,可自行往上翻找查看“Stack.c文件”的内容)

定义栈的结构:

typedef char STDataType;
typedef struct Stack
{
   STDataType* arr;
   int top;//指向栈顶的位置,也表示有效元素个数
   int capacity;//栈的容量
}ST;

具体解题代码:

//运用数据结构——栈
bool isValid(char* s) {
    ST st;
    StackInit(&st);//初始化栈
    char* pi = s;//遍历字符串
    while(*pi != '\0')
    {
        //若遍历到左括号
        if(*pi == '(' || *pi == '[' || *pi == '{')
        {
            StackPush(&st,*pi);//左括号入栈
        }
        //若遍历到右括号
        else
        {
            //若此时栈为空,只有右括号则不可能形成有效字符串
            if(StackEmpty(&st))
            {
                StackDestroy(&st);
                return false;
            }
            //栈不为空
            char top = StackTop(&st);
            if((top == '(' && *pi != ')')
            || (top == '[' && *pi != ']')
            || (top == '{' && *pi != '}'))
            {
                //遍历到的任一右括号如果与栈顶的左括号不匹配,则也不可能形成有效字符串
                StackDestroy(&st);
                return false;
            }
            //右括号与栈顶匹配成功,则栈顶的左括号出栈,更换新的栈顶继续匹配
            StackPop(&st);
        }
        //匹配成功后继续往后遍历
        pi++;
    }
    //遍历结束后得考虑栈内元素是否为空,为空方可为有效字符串
    bool ret = StackEmpty(&st) ? true : false;
    StackDestroy(&st);
    return ret;
    //以上每个“return”前记得销毁栈
}

2.用队列实现栈

 225. 用队列实现栈 - 力扣(LeetCode)

 

解题思路: 

对于队列的基本实现方法这里也不一一展示,可以返回观看Queue.c文件部分的内容。

出栈:要用两个队列实现栈功能,我们知道队列满足先进先出,而栈是先进后出的,假设往一个队列里入队1、2、3、4,正常情况下出队也是按照相同的顺序,但是我们要实现先进后出的栈,因此4必须先出来,所以我们就要借助第二个队列,将前面三个数也就是前面size-1的数入队到第二个空队列中,然后剩余的一个保存后出队,最后返回保存的数即可。

入栈:由出栈的思路可以知道,空队列是用于保存前size-1个数的,因此要入栈只能插入到非空队列中。

取栈顶元素:由于入栈时插入的是不为空的队列,因此直接取不为空队列的队尾元素即可。

先定义队列的结构

typedef int QDataType;
typedef struct QueueNode
{
    QDataType data;
    struct QueueNode* next;
}QueueNode;

typedef struct Queue
{
    QueueNode* phead;
    QueueNode* ptail;
}Queue;

以下是实现题目要求的功能

1.初始化两个队列

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


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

2.实现入栈功能

void myStackPush(MyStack* obj, int x) {
    //往不为空的队列中插入数据
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else{
        QueuePush(&obj->q2,x);
    }
}

3.出栈并返回栈顶元素

int myStackPop(MyStack* obj) {
    //将不为空队列中前size-1个数据挪到另一个队列中
    //再将最后一个数据出队列
    Queue* emp = &obj->q1;
    Queue* noneEmp = &obj->q2;
    if(QueueEmpty(&obj->q2))
    {
        emp = &obj->q2;
        noneEmp = &obj->q1;
    }
    while(QueueSize(noneEmp)>1)
    {
        //取非空队列首元素插入空队列
        QueuePush(emp,QueueFront(noneEmp));
        //插入后将非空队列首元素删除
        QueuePop(noneEmp);
    }
    //此时非空队列只剩下要出队的那个元素
    int top = QueueFront(noneEmp);
    QueuePop(noneEmp);
    return top;
}

4.取栈顶元素

int myStackTop(MyStack* obj) {
   //取非空队列的队尾元素
   if(!QueueEmpty(&obj->q1))
   {
       return QueueBack(&obj->q1);
   }
   else{
       return QueueBack(&obj->q2);
   }
}

5.判断栈是否为空

bool myStackEmpty(MyStack* obj) {
    //若两个队列均为空则栈才为空
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

6.栈的销毁

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

3.用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

 

 解题思路:

栈的功能实现函数回看前面Stack.c文件的内容

栈的进出法则是先进后出(后进先出),而队列是先进先出。假设将1、2、3、4压入栈,栈底就是1,栈顶则是4,按照正常情况应该是4先出,而我们要实现队列,则应该1先出,此时我们就要借助另一个栈了,将原栈里面的数全部压入第二个栈,此时会惊奇的发现,第二个栈的栈顶元素变成了1,栈底元素变成了4,就可以1234依次出栈,这不就是我们想要实现出队的顺序吗?那我们想要入队列的时候,数据应该压入哪个栈呢,显然是压入第一个栈,因为第二个栈是要出“队首”的数据,如果新数据压入第二个栈就会出现“插队”的情况。总结起来整体过程就是,数据先入第一个栈,要出队的时候把第一个栈的所有元素压入第二个栈,由第二个栈出数据;想要再插入数据时,插入第一个栈,等到第二个栈的数据全部出完后,第一个栈的所有数据再压入第二个栈,周而复始。可以发现,第一个栈是用来专门“入队列”的,命名为PushST;第二个栈则是专门用来“出队列”的,命名为PopST。

 定义栈的结构

typedef int STDataType;
typedef struct Stack
{
    STDataType*arr;
    int top;
    int capacity;
}ST;

1.用两个栈定义队列初始化并返回

typedef struct {
    ST PushST;
    ST PopST;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&pq->PushST);
    StackInit(&pq->PopST);

    return pq;
}

2.插入元素到队尾

void myQueuePush(MyQueue* obj, int x) {
    //往PushST中插入数据
    StackPush(&obj->PushST,x);
}

3.出队列并返回元素

//检查PopST是否为空
//不为空则直接出PopST栈顶
//为空,PushST的数据全部导入PopST,再出PopST栈顶
int myQueuePop(MyQueue* obj) {
    if(StackEmpty(&obj->PopST))
    {
        //导数据
        while(StackSize(&obj->PushST))
        {
            StackPush(&obj->PopST,StackTop(&obj->PushST));
            StackPop(&obj->PushST);
        }
    }
    int top = StackTop(&obj->PopST);
    StackPop(&obj->PopST);
    return top;
}

4.返回队列开头的元素

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

5.判断队列是否为空

bool myQueueEmpty(MyQueue* obj) {
    //两个栈均为空,则队列才为空
    return StackEmpty(&obj->PushST) && StackEmpty(&obj->PopST);
}

6.销毁队列

void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->PushST);
    StackDestroy(&obj->PopST);
    free(obj);
    obj = NULL;
}

### 使用两个实现队列的Java代码示例 通过使用两个来模拟队列的行为是一种常见的数据结构设计方法。以下是基于此逻辑的一个具体实现: #### 实现原理 为了使两个能够完成队列的功能,可以定义一个输入 `inStack` 一个输出 `outStack`。当执行入队操作时,元素被压入 `inStack`;而当需要出队时,则将所有元素从 `inStack` 转移到 `outStack` 并弹出顶部元素。 ```java import java.util.Stack; class MyQueue { private Stack<Integer> inStack; private Stack<Integer> outStack; /** Initialize your data structure here. */ public MyQueue() { inStack = new Stack<>(); outStack = new Stack<>(); } /** Push element x to the back of queue. */ public void push(int x) { inStack.push(x); } /** Removes the element from in front of queue and returns that element. */ public int pop() { if (outStack.isEmpty()) { while (!inStack.isEmpty()) { outStack.push(inStack.pop()); } } return outStack.pop(); } /** Get the front element. */ public int peek() { if (outStack.isEmpty()) { while (!inStack.isEmpty()) { outStack.push(inStack.pop()); } } return outStack.peek(); } /** Returns whether the queue is empty. */ public boolean empty() { return inStack.isEmpty() && outStack.isEmpty(); } } ``` 上述代码展示了如何利用两个来构建一个基本的队列功能[^1]。其中的关键在于理解何时以及如何在两个之间转移数据以保持 FIFO 的顺序。 #### 测试用例 下面是一个简单的测试例子用于验证该类的工作情况: ```java public class Main { public static void main(String[] args) { MyQueue obj = new MyQueue(); obj.push(1); obj.push(2); System.out.println(obj.peek()); // 输出 1 System.out.println(obj.pop()); // 输出 1 System.out.println(obj.empty()); // 输出 false } } ``` 这段程序创建了一个新的队列对象并进行了几个基础的操作演示其行为是否符合预期[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值