栈和队列刷题篇
大家好,这里是小编的博客频道
小编的博客:就爱学编程
很高兴在
CSDN
这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!
目录
- 1.括号匹配问题
- (1)题目描述
- (2)解题思路
- 2.循环队列
- (1)题目描述
- (2)解题思路
- 3.用队列实现栈
- (1)题目描述
- (2)解题思路
- 4.用两个栈实现队列
- (1)题目描述
- (2)解题思路
- 快乐的时光总是短暂,咱们下篇博文再见啦!!!如果小编的文章会对你有帮助的话不要忘了,记得给小编点赞、收藏支持一下,在此非常感谢!!!
废话不多说,我们直接看题。
1.括号匹配问题
(1)题目描述
(2)解题思路
- 左括号入栈,右括号出栈,一一配对
- 我们先对字符串的每个元素进行判断------如果是左括号就让左括号入栈,如果是右括号就出栈顶元素进行匹配------如果是一一匹配就是true,不是就是false
代码实现:
#define MAXCAPACITY 4
typedef char Datastyle;
typedef struct stack {
Datastyle* a;
int top;
int capacity;
}ST;
void STInit(ST* ps);
void STDestory(ST* ps);
void STPush(ST* ps, Datastyle x);
void STPop(ST* ps);
Datastyle STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
//初始化栈
void STInit(ST* ps) {
assert(ps);
Datastyle* temp = (Datastyle*)malloc(MAXCAPACITY * sizeof(Datastyle));
if (temp == NULL) {
perror("malloc fail");
exit(-1);
}
ps->a = temp;
ps->capacity = MAXCAPACITY;
ps->top = 0;
}
//销毁栈
void STDestory(ST* ps){
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
//插入数据(从栈顶)----(入栈,压栈)
void STPush(ST* ps, Datastyle x) {
assert(ps);
//判断是否满了
if (ps->top == ps->capacity) {
Datastyle* temp = (Datastyle*)realloc(ps->a, 2 * ps->capacity * sizeof(Datastyle)); //扩容为当前容量的两倍比较合理
if (temp == NULL) {
perror("realloc fail");
return;
}
ps->a = temp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
//判空
bool STEmpty(ST* ps) {
return (ps->top == 0);
}
//删除数据(从栈顶)----(出栈)
void STPop(ST* ps) {
assert(ps && !STEmpty(ps));
--ps->top;
}
//访问栈顶元素
Datastyle STTop(ST* ps) {
return ps->a[ps->top - 1];
}
//得出栈的元素个数
int STSize(ST* ps) {
assert(ps);
return ps->top;
}
bool isValid(char* s) {
//求解这道题的思路是:我们先对字符串的每个元素进行判断------如果是左括号就让左括号入栈,如果是右括号就出栈顶元素进行匹配------如果是一一匹配就是true,不是就是false
//1、创建一个栈
ST st;
//2、初始化栈
STInit(&st);
//3、开始判断
while(*s){
if(*s == '[' || *s == '{' || *s == '('){
STPush(&st, *s); //入栈
}
else{
if(STEmpty(&st))
{
//4、销毁栈
STDestory(&st);
return false;
} //如果一开始就没有左括号进栈就说明括号不可能匹配的上(这里可以用判空函数进行判断也可以用计数函数是否为零进行判断)
char top = STTop(&st); //储存栈顶元素
STPop(&st); //出栈
if((*s == ']' && top != '[')
|| (*s == '}' && top != '{')
|| (*s == ')' && top != '('))
{
//4、销毁栈
STDestory(&st);
return false;
}
}
s++; //不管进入哪个语句都要使得s++以用来进行循环
}
if(!STEmpty(&st)){ //如果以上循环出来就只剩两种可能性--------(1)字符串中只有左括号,不匹配;(2)一一匹配,循环出来时栈为空
//4、销毁栈
STDestory(&st);
return false;
}
//4、销毁栈
STDestory(&st);
return true;
}
2.循环队列
(1)题目描述
(2)解题思路
- 在循环队列中,当队列为空,可知front=rear;而当所有队列空间全占满时,也有 front=rear。为了区别这两种情况,假设队列使用的数组有 capacity 个存储空间,则此时规定循环队列最多只能有capacity−1 个队列元素,当循环队列中只剩下一个空存储单元时,则表示队列已满。根据以上可知,队列判空的条件是 front=rear,而队列判满的条件是 front(rear+1)modcapacity。对于一个固定大小的数组,只要知道队尾 rear 与队首 front,即可计算出队列当前的长度(rear−front+capacity)modcapacity
循环队列的属性如下:
elements
:一个固定大小的数组,用于保存循环队列的元素。
capacity
:循环队列的容量,即队列中最多可以容纳的元素数量。
front
:队列首元素对应的数组的索引。
rear
:队列尾元素对应的索引的下一个索引。
循环队列的接口方法如下:
MyCircularQueue(int k)
: 初始化队列,同时base 数组的空间初始化大小为 k+1。front,rear 全部初始化为 0。
enQueue(int value)
:在队列的尾部插入一个元素,并同时将队尾的索引 rear 更新为 (rear+1)modcapacity。
deQueue()
:从队首取出一个元素,并同时将队首的索引 front 更新为 (front+1)modcapacity。
Front()
:返回队首的元素,需要检测队列是否为空。
Rear()
:返回队尾的元素,需要检测队列是否为空。
isEmpty()
:检测队列是否为空,根据之前的定义只需判断 rear 是否等于 front。
isFull()
:检测队列是否已满,根据之前的定义只需判断 front 是否等于 (rear+1)modcapacity。
代码实现:
typedef struct {
int* a;
int k;
int front;
int rear;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* ps = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
if (ps == NULL) {
perror("malloc fail");
return NULL;
}
int* ptr = (int*)malloc(sizeof(int) * (k + 1));
if (ptr == NULL) {
perror("malloc fail");
return NULL;
}
ps->a = ptr;
ps->front = ps->rear = 0;
ps->k = k;
return ps;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return ((obj->rear + 1) % (obj->k + 1)) == obj->front;
}
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 + obj->k) % (obj->k + 1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
obj->a = NULL;
free(obj);
obj = NULL;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if (!myCircularQueueIsFull(obj)) {
obj->a[obj->rear] = value;
obj->rear++;
obj->rear %= (obj->k + 1);
return true;
}
return false;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (!myCircularQueueIsEmpty(obj)) {
obj->a[obj->front++] = 0;
obj->front %= (obj->k + 1);
return true;
}
return false;
}
(1)题目描述
(2)解题思路
- 为了满足栈的特性,即最后入栈的元素最先出栈,在使用队列实现栈时,应满足队列前端的元素是最后入栈的元素。可以使用两个队列实现栈的操作,其中
queue 1
用于存储栈内的元素,queue 2
作为入栈操作的辅助队列。- 入栈操作时,首先将元素入队到
queue 2
,然后将queue 1
的全部元素依次出队并入队到queue 2
,此时queue 2
的前端的元素即为新入栈的元素,再将queue 1
和queue 2
互换,则queue 1
的元素即为栈内的元素,queue 1
的前端和后端分别对应栈顶和栈底。由于每次入栈操作都确保queue 1
的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。出栈操作只需要移除queue 1
的前端元素并返回即可,获得栈顶元素操作只需要获得queue 1
的前端元素并返回即可(不移除元素)。由于queue 1
用于存储栈内的元素,判断栈是否为空时,只需要判断queue 1
是否为空即可。
代码实现:
typedef int QDatatype;
typedef struct QuequeNode {
QDatatype data;
struct QuequeNode* next;
}QNode;
typedef struct Queue{
QNode* head; //单链表的头指针作为队头
QNode* tail; //单链表的尾指针作为队尾
int size; //存储队列元素数量
}Que;
//初始化队列
void QInit(Que* ps) {
assert(ps);
ps->head = ps->tail = NULL;
ps->size = 0;
}
//销毁队列
void QDestroy(Que* ps) {
assert(ps);
QNode* cur = ps->head;
while (cur) {
QNode* next = cur->next;
free(cur);
cur = next;
}
ps->size = 0;
ps->head = ps->tail = NULL;
}
//插入数据(从队尾)------入队
void QPush(Que* ps, QDatatype x) {
assert(ps);
QNode* cur = (QNode*)malloc(sizeof(QNode));
if (cur == NULL) {
perror("malloc fail");
return;
}
if (ps->head == NULL) {
assert(ps->tail == NULL);
ps->head = ps->tail = cur;
}
else {
ps->tail->next = cur; //先赋值
ps->tail = cur; //再更新尾指针
}
cur->next = NULL;
cur->data = x;
ps->size++;
}
//判空
bool QEmpty(Que* ps) {
assert(ps);
return (ps->size == 0);
}
//删除数据(从对头)------出队
void QPop(Que* ps) {
assert(ps);
assert(!QEmpty(ps));
if (ps->head->next == NULL) {
free(ps->head);
ps->head = ps->tail = NULL;
ps->size = 0;
return;
}
QNode* next = ps->head->next;
free(ps->head);
ps->head = next;
ps->size--;
}
//得出队内元素数量
int QSize(Que* ps) {
assert(ps);
return (ps->size);
}
//得到队头元素的数据
QDatatype QFront(Que* ps) {
assert(ps && !QEmpty(ps));
return (ps->head->data);
}
//得到队尾元素的数据
QDatatype QBack(Que* ps) {
assert(ps && !QEmpty(ps));
return (ps->tail->data);
}
typedef struct {
Que q1;
Que q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* ptr = (MyStack*)malloc(sizeof(MyStack));
if(ptr == NULL){
perror("malloc fail");
return NULL;
}
QInit(&ptr->q1);
QInit(&ptr->q2);
return ptr;
}
void myStackPush(MyStack* obj, int x) {
if(QEmpty(&obj->q1)){
QPush(&obj->q2, x);
}
else{
QPush(&obj->q1, x);
}
}
int myStackPop(MyStack* obj) {
if(QEmpty(&obj->q1)){
while(QSize(&obj->q2) > 1){
QDatatype temp = QFront(&obj->q2);
QPop(&obj->q2);
QPush(&obj->q1, temp);
}
QDatatype top = QBack(&obj->q2);
QPop(&obj->q2);
return top;
}
else{
while(QSize(&obj->q1) > 1){
QDatatype temp = QFront(&obj->q1);
QPop(&obj->q1);
QPush(&obj->q2, temp);
}
QDatatype top = QBack(&obj->q1);
QPop(&obj->q1);
return top;
}
}
int myStackTop(MyStack* obj) {
if(QEmpty(&obj->q1)){
return QBack(&obj->q2);
}
return QBack(&obj->q1);
}
bool myStackEmpty(MyStack* obj) {
return QEmpty(&obj->q1) && QEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QDestroy(&obj->q1);
QDestroy(&obj->q2);
free(obj);
obj = NULL;
}
4.用两个栈实现队列
(1)题目描述
(2)解题思路
- 将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop 和 peek 操作。
- 每次
pop
或peek
时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。
代码实现:
#define MAXCAPACITY 4
typedef int Datastyle;
typedef struct stack {
Datastyle* a;
int top;
int capacity;
}ST;
//初始化栈
void STInit(ST* ps) {
assert(ps);
Datastyle* temp = (Datastyle*)malloc(MAXCAPACITY * sizeof(Datastyle));
if (temp == NULL) {
perror("malloc fail");
exit(-1);
}
ps->a = temp;
ps->capacity = MAXCAPACITY;
ps->top = 0;
}
//销毁栈
void STDestory(ST* ps){
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
//插入数据(从栈顶)----(入栈,压栈)
void STPush(ST* ps, Datastyle x) {
assert(ps);
//判断是否满了
if (ps->top == ps->capacity) {
Datastyle* temp = (Datastyle*)realloc(ps->a, 2 * ps->capacity * sizeof(Datastyle)); //扩容为当前容量的两倍比较合理
if (temp == NULL) {
perror("realloc fail");
return;
}
ps->capacity *= 2;
ps->a = temp;
}
ps->a[ps->top++] = x;
}
//判空
bool STEmpty(ST* ps) {
return (ps->top == 0);
}
//删除数据(从栈顶)----(出栈)
void STPop(ST* ps) {
assert(ps && !STEmpty(ps));
--ps->top;
}
//访问栈顶元素
Datastyle STTop(ST* ps) {
return ps->a[ps->top - 1];
}
//得出栈的元素个数
int STSize(ST* ps) {
assert(ps);
return ps->top;
}
typedef struct {
ST stpush; //stpush专门用来存储数据,只有在stpop为空时进行出数据至st2
ST stpop; //stpop专门用来出数据,只有当其为空时从stpush拿出数据进行存储
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* ptr = (MyQueue*) malloc(sizeof(MyQueue));
if(ptr == NULL){
perror("malloc fail");
return NULL;
}
STInit(&ptr->stpush);
STInit(&ptr->stpop);
return ptr;
}
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->stpush, x);
}
int myQueuePop(MyQueue* obj) {
if(STEmpty(&obj->stpop)){
while(!STEmpty(&obj->stpush)){
Datastyle temp = STTop(&obj->stpush);
STPop(&obj->stpush);
STPush(&obj->stpop, temp);
}
}
Datastyle top = STTop(&obj->stpop);
STPop(&obj->stpop);
return top;
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->stpop)){
while(!STEmpty(&obj->stpush)){
Datastyle temp = STTop(&obj->stpush);
STPop(&obj->stpush);
STPush(&obj->stpop, temp);
}
}
return STTop(&obj->stpop);
}
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->stpush) && STEmpty(&obj->stpop);
}
void myQueueFree(MyQueue* obj) {
STDestory(&obj->stpush);
STDestory(&obj->stpop);
free(obj);
obj = NULL;
}