数据结构第七讲:栈和队列OJ题
- 1.有效的括号
- 2.用队列实现栈
- 3.用栈实现队列
- 4.设计循环队列
1.有效的括号
链接: OJ题目链接
typedef char StackDataType;
typedef struct Stack
{
StackDataType* arr;//使用一个指针来指向开辟的数组
int capacity;//保存数组的空间大小
int top;//指向栈顶
}Stack;
//栈的初始化
void Init(Stack* ps)
{
assert(ps);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
//栈的销毁
void Destory(Stack* ps)
{
assert(ps);
//注意:这个要加上if进行判断,为了确保arr数组不是指向NULL
if(ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
//栈的插入
void StackPush(Stack* ps, StackDataType x)
{
assert(ps);
//因为只有栈的插入才需要开辟空间,所以开辟结点空间不必封装成一个函数
if (ps->top == ps->capacity)
{
//空间不足,需要开辟
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
StackDataType* parr = (StackDataType*)realloc(ps->arr, newcapacity * sizeof(StackDataType));
if (parr == NULL)
{
perror("malloc faile!");
exit(1);
}
ps->arr = parr;
ps->capacity = newcapacity;
}
ps->arr[ps->top++] = x;
}
//栈的删除
void StackPop(Stack* ps)
{
//栈为NULL时不能删除,栈中没有数据时不能删除
assert(ps && ps->top);
--ps->top;
}
//取栈顶元素
StackDataType StackPrint(Stack* ps)
{
assert(ps && ps->top);
return ps->arr[--ps->top];
}
//获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
--------------------------------------------------------------------------
//下面才是实现思路
bool isValid(char* s) {
Stack ps;
//先对栈进行初始化
Init(&ps);
while(*s)
{
if(*s=='(' || *s=='{' || *s=='[')
{
//三种情况,进行插入
StackPush(&ps, *s);
}
else
{
if((ps.top == 0) || (ps.top==0 && *s!='\0')) return false;
StackDataType a = StackPrint(&ps);
if( (a=='(' && *s==')') ||
(a=='[' && *s==']') ||
(a=='{' && *s=='}') );
else
{
//不匹配时,直接返回false
return false;
}
}
s++;
}
if(ps.top!=0 && *s=='\0') return false;
return true;
}
2.用队列实现栈
链接: OJ题目链接
//结点结构体
typedef int QueueDataType;
typedef struct QueueNode
{
//和链表一样,也需要结点进行链接
QueueDataType val;
struct QueueNode* next;
}QueueNode;
//队列结构体
typedef struct Queue
{
QueueNode* head;//指向队列的头部,方便删除数据
QueueNode* tail;//指向队列的尾部,方便插入数据
int size;//用来记录有效数据的个数
}Queue;
//队列初始化
void Init(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
//销毁队列
void Destory(Queue* pq)
{
assert(pq);
QueueNode* prev = pq->head;
while (prev)
{
QueueNode* next = prev->next;
free(prev);
prev = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
//入队列
void QueuePush(Queue* pq, QueueDataType x)
{
assert(pq);
//只有入队列需要开辟结点空间
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
perror("malloc faile!");
exit(1);
}
newnode->val = x;
newnode->next = NULL;
//要分情况讨论:当队列一开始没有一个结点时
if (pq->head == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
//直接插入到末尾即可
//head ... tail newnode
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
//出队列
void QueuePop(Queue* pq)
{
assert(pq && pq->head);
//出队列要求从队列开头进行删除
//此时要分情况讨论:当只具有一个结点时
if (pq->head == pq->tail)
{
free(pq->head);
pq->head = pq->tail == NULL;
}
else
{
//pq->head pq->head->next
QueueNode* tmp = pq->head->next;
free(pq->head);
pq->head = tmp;
}
--pq->size;
}
//取队列头结点数据
QueueDataType QueueFront(Queue* pq)
{
assert(pq && pq->head);
return pq->head->val;
}
//取队列尾节点数据
QueueDataType QueueBack(Queue* pq)
{
assert(pq && pq->head && pq->tail);
return pq->tail->val;
}
//队列有效元素的个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
//检查队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
///
typedef struct {
//需要创建两个队列
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
Init(&pst->q1);
Init(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
//将数据压入栈,首先要找到那个不为空的队列
//假设第一个队列不为空
Queue* none = &obj->q1;
Queue* emp = &obj->q2;
if(QueueEmpty(&obj->q1))
{
none = &obj->q2;
emp = &obj->q1;
}
QueuePush(none, x);
}
int myStackPop(MyStack* obj) {
//出栈
Queue* none = &obj->q1;
Queue* emp = &obj->q2;
if(QueueEmpty(&obj->q1))
{
none = &obj->q2;
emp = &obj->q1;
}
//先将size-1个数据保存到空的队列中
while(QueueSize(none) > 1)
{
int data = QueueFront(none);
QueuePush(emp, data);
QueuePop(none);
}
int data = QueueFront(none);
QueuePop(none);
return data;
}
int myStackTop(MyStack* obj) {
//取栈顶元素
Queue* none = &obj->q1;
Queue* emp = &obj->q2;
if(QueueEmpty(&obj->q1))
{
none = &obj->q2;
emp = &obj->q1;
}
return QueueBack(none);
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
Destory(&obj->q1);
Destory(&obj->q2);
free(obj);
obj = NULL;
}
3.用栈实现队列
链接: OJ题目链接
typedef int StackDataType;
typedef struct Stack
{
StackDataType* arr;//使用一个指针来指向开辟的数组
int capacity;//保存数组的空间大小
int top;//指向栈顶
}Stack;
//栈的初始化
void Init(Stack* ps)
{
assert(ps);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
//栈的销毁
void Destory(Stack* ps)
{
assert(ps);
//注意:这个要加上if进行判断,为了确保arr数组不是指向NULL
if(ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
//栈的插入
void StackPush(Stack* ps, StackDataType x)
{
assert(ps);
//因为只有栈的插入才需要开辟空间,所以开辟结点空间不必封装成一个函数
if (ps->top == ps->capacity)
{
//空间不足,需要开辟
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
StackDataType* parr = (StackDataType*)realloc(ps->arr, newcapacity * sizeof(StackDataType));
if (parr == NULL)
{
perror("malloc faile!");
exit(1);
}
ps->arr = parr;
ps->capacity = newcapacity;
}
ps->arr[ps->top++] = x;
}
//栈的删除
void StackPop(Stack* ps)
{
//栈为NULL时不能删除,栈中没有数据时不能删除
assert(ps && ps->top);
--ps->top;
}
//取栈顶元素
StackDataType StackPrint(Stack* ps)
{
assert(ps && ps->top);
return ps->arr[ps->top-1];
}
//获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
//检查栈是否为空
bool StackCheck(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
/
typedef struct {
//首先要创建出两个栈结构体
Stack push;
Stack pop;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));
Init(&queue->push);
Init(&queue->pop);
return queue;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->push, x);
}
int myQueuePop(MyQueue* obj) {
//删除元素要在pop队列中删除
//此时要进行讨论
//当pop链表还不为空时,直接删除一个元素即可
if(!StackCheck(&obj->pop))
{
int data = StackPrint(&obj->pop);
StackPop(&obj->pop);
return data;
}
//当pop链表为空时,需要将push链表中的数据移到pop链表中
//先将元素全部移到pop队列中
while(!StackCheck(&obj->push))
{
int data = StackPrint(&obj->push);
StackPush(&obj->pop, data);
StackPop(&obj->push);
}
//然后删除pop中的一个元素即可
int data = StackPrint(&obj->pop);
StackPop(&obj->pop);
return data;
}
int myQueuePeek(MyQueue* obj) {
//返回队列开头的元素
//此时也要进行检查
if(!StackCheck(&obj->pop))
{
return StackPrint(&obj->pop);
}
//当pop链表为空时,需要将push链表中的数据移到pop链表中
//先将元素全部移到pop队列中
while(!StackCheck(&obj->push))
{
int data = StackPrint(&obj->push);
StackPush(&obj->pop, data);
StackPop(&obj->push);
}
return StackPrint(&obj->pop);
}
bool myQueueEmpty(MyQueue* obj) {
//检查队列是否为空
return StackCheck(&obj->push) && StackCheck(&obj->pop);
}
void myQueueFree(MyQueue* obj) {
Destory(&obj->push);
Destory(&obj->pop);
free(obj);
obj = NULL;
}
4.设计循环队列
链接: OJ题目链接
要区分队列已满和队列中无数据就要多开辟一块空间,但是那一块空间只是一个指代作用,其实并不会被使用
typedef struct {
int *arr;
int front;
int rear;
int capacity;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* tmp = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
//需要多创建一个int字节的空间,因为后边还要使用
tmp->arr = (int*)malloc(sizeof(int) * (k+1));
tmp->front = tmp->rear = 0;
tmp->capacity = k;
return tmp;
}
//判断循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear + 1) % (obj->capacity + 1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
//当队列已满时不能进行插入数据
if(myCircularQueueIsFull(obj))
{
return false;
}
//当循环队列不满时,在rear位置插入数据即可
obj->arr[obj->rear++] = value;
//如果rear的结果超出了数组的大小,要对rear的值进行一个更正
obj->rear %= (obj->capacity+1);
return true;
}
//判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->rear == obj->front;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
//删除数据时直接移动front的指向即可
//当队列为空时不能够执行删除操作
if(myCircularQueueIsEmpty(obj));
{
return false;
}
obj->front++;
//对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 - 1;
}
return obj->arr[prev];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
obj = NULL;
}