【数据结构初阶】队列和栈OJ题

⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:数据结构初阶
⭐代码仓库:Data Structure
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!


一、有效的括号

(一)题目描述

在这里插入图片描述


(二)解题思路

在这里插入图片描述
我们将s数组里面的左半边括号全部放入栈中,再进行栈的匹配,将栈里面的元素一个一个拿出来存到top里与接下来的s数组进行一个个匹配,匹配不成功则返回false,全都匹配成功则匹配成功,这里的细节是需要将原本写的栈的代码全部粘贴过来,再根据我们需要匹配信息来进行运用这些接口函数。


(三)解题代码

typedef char StackDataType;

typedef struct Stack {
	StackDataType* a;
	int top; // 栈顶
	int capacity; // 容量
}ST;


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

//压栈
void StackPush(ST* ps, StackDataType x);

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

//计算栈中有多少个
int StackSize(ST* ps);

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

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

//栈内的元素
StackDataType StackShow(ST* ps);


//初始化
void StackInit(ST* ps) {
	assert(ps);
	//先开辟4个空间
	ps->a = (StackDataType*)malloc(sizeof(StackDataType) * 4);
	if (ps->a == NULL) {
		perror("malloc::ps->a");
		return;
	}
	ps->capacity = 4;
	ps->top = 0; //栈顶后一个位置
	//ps->top = -1; //栈顶本身的位置
}

//压栈
void StackPush(ST* ps, StackDataType x) {
	assert(ps);
	//assert(!(StackEmpty(ps)));

	// 判断是否需要扩容
	if (ps->capacity == ps->top) {
		//扩容
		StackDataType* temp = (StackDataType*)realloc(ps->a, sizeof(StackDataType) * ps->capacity * 2);
		if (temp == NULL) {
			perror("malloc failed");
			return;
		}
		ps->a = temp;
		ps->capacity *= 2;
	}
	
	ps->a[ps->top] = x;
	ps->top++;
}

//出栈
void StackPop(ST* ps) {
	assert(ps);
	assert(!(StackEmpty(ps)));
	ps->top--;
}

//计算栈中有多少个
int StackSize(ST* ps) {
	assert(ps);

	return ps->top;
}

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

	return ps->top == 0;//是空返回false,不是空返回true
}

//销毁
void StackDestroy(ST* ps) {
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//栈内的元素
StackDataType StackShow(ST* ps) {
	assert(ps);
	return ps->a[ps->top - 1];
}

bool isValid(char * s){
    ST st;
    StackInit(&st);
    while(*s != '\0')
    {
        if(*s == '{' || *s == '(' || *s == '[')
        {
            StackPush(&st, *s);
        }
        else{

            if(StackEmpty(&st)){
                StackDestroy(&st);
                return false;
            }

            char top = StackShow(&st);
            StackPop(&st);
            if((*s == ')' && top != '(')
            || (*s=='}' && top != '{')
            || (*s==']' && top != '['))
            {
                StackDestroy(&st);
                return false;
            }
        }
        ++s;
    }

    bool ret =StackEmpty(&st);
    StackDestroy(&st);
    return ret;

}

二、用队列实现栈

(一)题目描述

在这里插入图片描述


(二)解题思路

在这里插入图片描述
看起来似乎很难,但是我们要仔细思考一下,既然要用两个队列实现一个栈的要求,那我们知道队列是先进先出,也就是从队尾进队头出;而栈是后进先出,也就是都从栈顶进入,都从栈顶出。那我们有一个思路,假设队列中总共有n项数据,我们先将前n-1项数据倒入另一个队列中,不就自然剩下最末尾的元素,我们将它进行pop,拿出来即可。所以我们就可以通过这个想法进行空队列,有数据队列进行不断的更迭,将末尾数据取出来;而此时我们又想插入数据怎么办?那当然是插入到有数据的队列后面了,为什么?因为我们知道,我们要模拟的栈是后进先出,也就是说我们新加入的元素需要下一步就出来,所以我们插入到队列的尾,再进行倒数据进行出末尾数据即可。


(三)解题代码

typedef int QueueDataType;

typedef struct QueueNode {
	struct QueueNode* next;
	QueueDataType data;
}QNode;

typedef struct Queue {
	QNode* head;
	QNode* tail;
	QueueDataType size;
}Queue;

//初始化
void QueueInit(Queue* pq); //改变结构体成员就用结构体的指针即可

//销毁链表
void QueueDestroy(Queue* pq);

//进队列
void QueuePush(Queue* pq, QueueDataType x);

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

//计算长度
int QueueSize(Queue* pq);

//判断是否为空
bool QueueEmpty(Queue* pq);

//队头
QueueDataType QueueFront(Queue* pq);

//队尾
QueueDataType QueueBack(Queue* pq);

//初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//销毁链表
void QueueDestroy(Queue* pq) {
	assert(pq);
	QNode* cur = pq->head;
	while (cur) {
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

//进队列
void QueuePush(Queue* pq, QueueDataType x) {
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL) {
		perror("malloc failed");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;

	if (pq->head == NULL) {//链表内部啥也没有
		assert(pq->tail == NULL);
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
    pq->size++;
}

//出队列
void QueuePop(Queue* pq) {
	assert(pq);
	assert(pq->head != NULL);
	/*QNode* cur = pq->head;
	QNode* next = cur->next;
	free(cur);
	pq->head = next;
	if (pq->head == NULL) {
		pq->tail = NULL;
	}
	pq->size--;*/

	if (pq->head->next == NULL) {
		free(pq->head);
		pq->tail = pq->head = NULL;
	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}

//计算长度
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}

//判断是否为空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->head == NULL && pq->tail == NULL;
}

//取队头
QueueDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

//取队尾
QueueDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}


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


MyStack* myStackCreate() {
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    if(pst == NULL){
        perror("malloc fail");
        return NULL;
    }
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
    return pst;
}

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

int myStackPop(MyStack* obj) {
    Queue* EmptyQ = &obj->q1;
    Queue* NoneEmptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1)){
        EmptyQ = &obj->q2;
        NoneEmptyQ = &obj->q1;
    }
    //导数据
    while(QueueSize(NoneEmptyQ) > 1){//留最后一个数据
        QueuePush(EmptyQ, QueueFront(NoneEmptyQ));//队列头元素移动
        QueuePop(NoneEmptyQ);
    }
    int top = QueueFront(NoneEmptyQ);
    QueuePop(NoneEmptyQ);
    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);
}

三、用栈实现队列

(一)题目描述

在这里插入图片描述


(二)解题思路

在这里插入图片描述

在这里插入图片描述
我们有了前面一题的思路,那其实解决起来这道题目更加地轻松,我们如此规定:右边栈进行pop,左边栈进行push,也就是说,我们刚开始进行push数据的时候,是需要push在左边那个栈的,我们push进去1 2 3 4,而最后是从顶到底4 3 2 1这样的,那我们想要模拟队列,那就需要将4 3 2 1倒入右栈,从栈顶到栈低为1 2 3 4了,那就出栈顶即可,我们继续push也是同理,放在左栈,继续导数据进入右栈,再进行pop即可。


(三)解题代码

typedef int StackDataType;

typedef struct Stack {
	StackDataType* a;
	int top; // 栈顶
	int capacity; // 容量
}ST;

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

//压栈
void StackPush(ST* ps, StackDataType x);

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

//计算栈中有多少个
int StackSize(ST* ps);

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

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

//栈顶的元素
StackDataType StackShow(ST* ps);

//初始化
void StackInit(ST* ps) {
	assert(ps);
	//先开辟4个空间
	ps->a = (StackDataType*)malloc(sizeof(StackDataType) * 4);
	if (ps->a == NULL) {
		perror("malloc::ps->a");
		return;
	}
	ps->capacity = 4;
	ps->top = 0; //栈顶后一个位置

	//ps->top = -1; //栈顶本身的位置
}

//压栈
void StackPush(ST* ps, StackDataType x) {
	assert(ps);

	// 判断是否需要扩容
	if (ps->capacity == ps->top) {
		//扩容
		StackDataType* temp = (StackDataType*)realloc(ps->a, sizeof(StackDataType) * ps->capacity * 2);
		if (temp == NULL) {
			perror("malloc failed");
			return;
		}
		ps->a = temp;
		ps->capacity *= 2;
	}
	
	ps->a[ps->top] = x;
	ps->top++;
}

//出栈
void StackPop(ST* ps) {
	assert(ps);
	assert(!(StackEmpty(ps)));
	ps->top--;
}

//计算栈中有多少个
int StackSize(ST* ps) {
	assert(ps);

	return ps->top;
}

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

	return ps->top == 0;//是空返回false,不是空返回true
}

//销毁
void StackDestroy(ST* ps) {
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//栈顶的元素
StackDataType StackShow(ST* ps) {
	assert(ps);
	return ps->a[ps->top - 1];
}

typedef struct {
    ST pushst;
    ST popst;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    if(obj == NULL){
        perror("malloc failed");
        return NULL;
    }
    StackInit(&obj->pushst);
    StackInit(&obj->popst);
    return obj;
}

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

int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(&obj->popst)){
        //导数据
        while(!StackEmpty(&obj->pushst)){
            StackPush(&obj->popst, StackShow(&obj->pushst));
            StackPop(&obj->pushst);
        }
    }
    return StackShow(&obj->popst);
}

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

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

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

四、设计循环队列

(一)题目描述

在这里插入图片描述


(二)解题思路

在这里插入图片描述
先创建一个循环链表,其中a数组为开辟k+1个int型空间,头和尾都为头元素,也就是size=0的位置;判断数组是否为空仅仅判断头和尾是否相等;判断是否为满很简单,我们因为多开辟了一个区域,直接判断rear+1是否与头相等即可,那有很多朋友就要问了,那越界怎么办,那我们就用取余,将rear始终放在这k+1个空间内即可;关于放入数据这个函数的操作,先要判断这个数组是否已经放满了,没放满就先将数据放到rear当前位置,再将rear++往后走一位,这个往后走一位同样也是需要判断是否越界,直接进行取模操作即可;出数据就是简单的将front往后走即可。


(三)解题代码

typedef struct { 
    int* a;
    int front;
    int rear;
    int k;
} MyCircularQueue;


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

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;
    obj->a[obj->rear++] = value;
    obj->rear %= (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;
    return obj->a[(obj->rear-1 + obj->k+1)%(obj->k+1)];
}

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

总结

这四个关于栈和队列的经典OJ题,可谓是经典中的经典,在各大面试中都会考这几道经典题,都用的老的知识,新奇的思想,让我们知道老知识新用的妙处,都哥说过:“少即是多”,我们不能学的很快,学得很多,想要把所有的都在短时间内学完,实际上我们要不断学习旧知识,巩固好旧知识,这样才能成功。


客官,来个三连支持一下吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2022horse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值