⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:数据结构初阶
⭐代码仓库:Data Structure
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!
队列和栈OJ题
一、有效的括号
(一)题目描述
(二)解题思路
我们将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题,可谓是经典中的经典,在各大面试中都会考这几道经典题,都用的老的知识,新奇的思想,让我们知道老知识新用的妙处,都哥说过:“少即是多”,我们不能学的很快,学得很多,想要把所有的都在短时间内学完,实际上我们要不断学习旧知识,巩固好旧知识,这样才能成功。
客官,来个三连支持一下吧!