目录
前言:
一、有效括号
1.1思路
1.2代码实现
二、用队列实现栈
1.1思路
1.2代码实现
三、用栈实现队列
1.1思路
1.2代码实现
四、设计循环队列
1.1思路
1.2代码实现
前面介绍了栈和队列结构和操作,那么我们该如何好好利用所学的知识解决问题呢,光说不练假把式,接下来让我们破解一些练习题吧!
对于咱们对编程有兴趣或者成为陌生手段来说,刷题一般用牛客网和力扣
牛客网:牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网
力扣:力扣 (LeetCode) 全球极客挚爱的技术成长平台
20. 有效的括号 - 力扣(LeetCode)
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
把栈的结构、初始化、入栈、判空、出栈、取栈顶元素、获取栈的有效元素都导入题中
遍历栈,如果是(、[、{就入栈
是)、]、}就看是否为空,为空就false,
不为空则看是否匹配,匹配就出栈取,不匹配就false
往下走,最后销毁
//定义栈的结构
typedef int STDataType;
typedef struct stack
{
STDataType* arr;
int capacity; //栈的空间大小
int top; //栈顶
}ST;
//初始化
void STInit(ST* ps)
{
assert(ps);
ps->arr=NULL;
ps->capacity=ps->top=0;
}
//销毁
void STDestroy(ST* ps)
{
assert(ps);
if(ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
//入栈
void StackPush(ST* ps,STDataType x)
{
assert(ps);
//1.判断空间是否足够
if(ps->capacity == ps->top)
{
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;
}
//出栈
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
--ps->top;
}
//出栈
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->arr[ps->top-1];
}
//获取栈中有效元素个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool isValid(char* s) {
ST st;
// 初始化
STInit(&st);
//遍历字符串s
char *ps = s;
while(*ps != '\0')
{
//左括号,入栈
if(*ps == '(' || *ps == '[' || *ps == '{')
{
StackPush(&st,*ps);
}
else//右括号,和栈顶元素比较是否匹配)]}
{
//栈为空,直接返回false
if(StackEmpty(&st))
{
return false;
}
//栈不为空才能取栈顶元素
char ch = StackTop(&st);
if((*ps == ')' && ch == '(')
|| (*ps == ']' && ch == '[')
|| (*ps == '}' && ch == '{'))
{
StackPop(&st);
}
else
{
STDestroy(&st);
//不匹配
return false;
}
}
ps++;
}
bool ret = StackEmpty(&st) == true;
//销毁
STDestroy(&st);
return ret;
}
225. 用队列实现栈 - 力扣(LeetCode)
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回 true
;否则,返回 false
。把队列的结构、初始化、入栈、队列判空、出栈、取队头数据、取队尾数据、出栈、队列有效元素、销毁导入题中
创建两个队列Queue q1,Queue q2用来实现栈
创建一个栈pst,两个队列
往不为空的队列插入数据
EmpQ空队列,none非空队列
将none队列中size-1个数据导入到EmpQ
None只剩下一个数据---要出栈的数据
取栈顶元素---取none的队尾元素
判断q1和q2是否有元素,有返回False
销毁q1和q2,obj置为空
注意:
push to back
、peek/pop from front
、size
和 is empty
这些操作。//定义队列的结构
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* phead;
QueueNode* ptail;
int size;
}Queue;
//初始化
void QueueInit(Queue* ps)
{
assert(ps);
ps->phead = ps->ptail = NULL;
ps->size = 0;
}
//入栈
void QueuePush(Queue* ps, QDataType x)
{
assert(ps);
//创建一个节点newnode
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
//当队列为空时
if (ps->phead == NULL)
{
ps->phead = ps->ptail = newnode;
}
//队列不为空时
else
{
ps->ptail->next = newnode;
ps->ptail = newnode;
}
ps->size++;
}
//队列判空
bool QueueEmpty(Queue* ps)
{
assert(ps);
return ps->phead == NULL && ps->ptail == NULL;
}
//出栈
void QueuePop(Queue* ps)
{
assert(ps);
assert(! QueueEmpty(ps));
//只有一个节点时,避免ptail成为野指针
if (ps->ptail == ps->phead)
{
free(ps->phead);
ps->phead = ps->ptail = NULL;
}
else
{
//删除头元素
QueueNode* next = ps->phead->next;
free(ps->phead);
ps->phead = next;
}
ps->size--;
}
//取队头数据
QDataType QueueFront(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
return ps->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
return ps->ptail->data;
}
//队列有效元素
int Queuesize(Queue* ps)
{
assert(ps);
return ps->size;
}
//销毁队列
void QueueDestroy(Queue* ps)
{
assert(ps);
//assert(!QueueEmpty(ps));
QueueNode* pcur = ps->phead;
while (pcur)
{
QueueNode* next = pcur->next;
free(pcur);
pcur = next;
}
ps->phead = ps->ptail = NULL;
ps->size = 0;
}
//两个队列来实现栈
typedef struct {
Queue q1;
Queue q2;
} MyStack;
//STInit
MyStack* myStackCreate() {
MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
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* empQ = &obj->q1;
Queue* noneQ = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
noneQ = &obj->q1;
empQ = &obj->q2;
}
//将不为空队列中size-1个数据导入到空队列中
while(Queuesize(noneQ) > 1)
{
int front = QueueFront(noneQ);
QueuePush(empQ,front);
QueuePop(noneQ);
}
//非空队列中只剩下一个数据---要出栈的数据
int pop = QueueFront(noneQ);
QueuePop(noneQ);
return pop;
}
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);
obj = NULL;
}
232. 用栈实现队列 - 力扣(LeetCode)
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回 true
;否则,返回 false
说明:
push to top
, peek/pop from top
, size
, 和 is empty
操作是合法的。把栈的初始化、销毁、入栈、判空、出栈、取栈顶值、获取栈有效个数都插入题中
创建两个栈:进数据pushST,出数据popST
创建一个队列,初始化
插入数据,检查popST是否为空,为空直接出,不为空pushST导入到popST,再出数据
取队头元素,取栈顶,删除栈顶元素并返回栈顶数据
判断队列是否为空
销毁队列
//定义栈的结构
typedef int STDataType;
typedef struct stack
{
STDataType* arr;
int capacity; //栈的空间大小
int top; //栈顶
}ST;
//初始化
void STInit(ST* ps)
{
assert(ps);
ps->arr=NULL;
ps->capacity=ps->top=0;
}
//销毁
void STDestroy(ST* ps)
{
assert(ps);
if(ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
//入栈
void StackPush(ST* ps,STDataType x)
{
assert(ps);
//1.判断空间是否足够
if(ps->capacity == ps->top)
{
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;
}
//出栈
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
--ps->top;
}
//取栈顶元素
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->arr[ps->top-1];
}
//获取栈中有效元素个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
/
typedef struct {
ST pushST;
ST popST;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* pst = (MyQueue*)malloc(sizeof(MyQueue));
STInit(&pst->pushST);
STInit(&pst->popST);
return pst;
}
//往pushST中插入数据
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushST,x);
}
//检查popST是否为空
// (1)不为空,直接出
// (2)为空,pushST导入到popST,再出数据
int myQueuePop(MyQueue* obj) {
if(StackEmpty(&obj->popST))
{
//导数据
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
//取栈顶,删除栈顶元素并返回栈顶数据
int top = StackTop(&obj->popST);
StackPop(&obj->popST);
return top;
}
//取队头元素
int myQueuePeek(MyQueue* obj) {
if(StackEmpty(&obj->popST));
{
//导数据
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
//取栈顶,删除栈顶元素并返回栈顶数据
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}
void myQueueFree(MyQueue* obj) {
STDestroy(&obj->pushST);
STDestroy(&obj->popST);
free(obj);
obj=NULL;
}
622. 设计循环队列 - 力扣(LeetCode)
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k)
: 构造器,设置队列长度为 k 。Front
: 从队首获取元素。如果队列为空,返回 -1 。Rear
: 获取队尾元素。如果队列为空,返回 -1 。enQueue(value)
: 向循环队列插入一个元素。如果成功插入则返回真。deQueue()
: 从循环队列中删除一个元素。如果成功删除则返回真。isEmpty()
: 检查循环队列是否为空。isFull()
: 检查循环队列是否已满。typedef struct {
int* arr;
int front;
int rear;
int capacity;
} MyCircularQueue;
//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* pst = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
pst->arr = (int*)malloc(sizeof(int)*(k+1));
pst->front = pst->rear = 0;
pst->capacity = k;
return pst;
}
//判断队列满了
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->capacity+1) == obj->front;
}
//插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
//队列满了不能插入数据
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->arr[obj->rear++] = value;
obj->rear %= obj->capacity+1;
return true;
}
//队列空了
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->rear == obj->front;
}
//删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
//队列不为空
if(myCircularQueueIsEmpty(obj))
{
return false;
}
//队列不为空
obj->front++;
obj->front %= obj->capacity+1;
return true;
}
//取队头元素
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->arr[obj->front];
}
//取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
int prev = obj->rear-1;
if(obj->rear == 0)
{
prev = obj->capacity;
}
return obj->arr[prev];
}
//队列销毁
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
obj = NULL;
}