大家好!这篇我给大家讲两个非常经典的题,希望这两个题能让你对栈和队列的理解更深。
用队列实现栈:
难度 简单 OJ链接
因为我们是C语言来做这道题,所以我们需要先写个栈。
因为题目中说是用两个队列,所以:
解题思路:
1.入数据,往不为空的队列入,保持另一个队列为空。
2.出数据,把不为空的队列的数据前N-1导入另外一个空队列,当剩下最后一个时,删掉。
入数据:
出数据:
然后,我们看一下题中的这个函数:
MyStack* myStackCreate() {
}
这个函数意思是调用函数来创建结构体,返回这个结构体的指针。
可能会有人这样来写:
MyStack* myStackCreate() {
MyStack st;
//......
return &st;
}
这个不对的,因为局部变量是在栈上创建的,函数结束时,会销毁,所以会变为野指针。
所以我们应该这样写:
MyStack* myStackCreate() {
MyStack* st=(MyStack*)malloc(sizeof(MyStack));
//用函数初始化队列
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
图应该这样:
下面我们来看myStackPush函数:
void myStackPush(MyStack* obj, int x) {
assert(obj);
//如果q1不为空,我们在q1Push,否则q2Push
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
如果都为空,我们随便在那个队列插入。
myStackPop函数:
int myStackPop(MyStack* obj) {
//假设q1为空,q2不为空
Queue* emptyQ=&obj->q1;
Queue* nonEmptyQ=&obj->q2;
//如果假设不成立,进行修改
if(!QueueEmpty(&obj->q1))
{
emptyQ=&obj->q2;
nonEmptyQ=&obj->q1;
}
//把非空的队列前N-1个数据导入空队列
while(QueueSize(nonEmptyQ)>1)
{
QDataType front=QueueFront(nonEmptyQ);
QueuePush(emptyQ,front);
//将非空队列的队头删除
QueuePop(nonEmptyQ);
}
QDataType top=QueueFront(nonEmptyQ);
QueuePop(nonEmptyQ);
return top;
}
题目中要我们返回栈顶元素。
然后看myStackTop函数:
取栈顶的元素非常简单,我们只需要看那个队列不为空,然后取队尾的那个数据。
int myStackTop(MyStack* obj) {
assert(obj);
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
myStackEmpty函数:
两个队列必须都为空,我们的栈才为空:
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
myStackFree函数:
void myStackFree(MyStack* obj) {
assert(obj);
//销毁队列
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
//销毁包含队列的结构体
free(obj);
}
在这里,我们不能只 free(obj),我们还要销毁队列,不然会造成内存泄漏。
完整代码如下:
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
//初始化函数的定义
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
//销毁函数的定义
void QueueDestroy(Queue* pq)
{
assert(pq);
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->tail == NULL;
}
//插入函数的定义
void QueuePush(Queue* pq,QDataType x)
{
assert(pq);
//创建一个节点
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
printf("malloc is fall\n");
exit(-1);
}
else
{
newnode->data = x;
newnode->next = NULL;
}
if (pq->head == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
//删除函数的定义
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
QDataType* next = pq->head->next;
free(pq->head);
pq->head = next;
if (pq->head == NULL)
{
pq->tail = NULL;
}
}
//取队头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
//队列里有多少数据
int QueueSize(Queue* pq)
{
assert(pq);
int n = 0;
QueueNode* cur = pq->head;
while (cur)
{
n++;
cur = cur->next;
}
return n;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
//调用一个函数来创建结构体,返回这个结构体的指针
MyStack* myStackCreate() {
MyStack* st=(MyStack*)malloc(sizeof(MyStack));
//用函数初始化队列
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x) {
assert(obj);
//如果q1不为空,我们在q1Push,否则q2Push
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
assert(obj);
//假设q1为空,q2不为空
Queue* emptyQ=&obj->q1;
Queue* nonEmptyQ=&obj->q2;
//如果假设不成立,进行修改
if(!QueueEmpty(&obj->q1))
{
emptyQ=&obj->q2;
nonEmptyQ=&obj->q1;
}
//把非空的队列前N-1个数据导入空队列
while(QueueSize(nonEmptyQ)>1)
{
QDataType front=QueueFront(nonEmptyQ);
QueuePush(emptyQ,front);
//将非空队列的队头删除
QueuePop(nonEmptyQ);
}
QDataType top=QueueFront(nonEmptyQ);
QueuePop(nonEmptyQ);
return top;
}
int myStackTop(MyStack* obj) {
assert(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) {
assert(obj);
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
用栈实现队列:
难度 简单 OJ链接
因为我们是C语言来做这道题,所以我们需要先写个队列。
因为题目中说是用两个队列,所以:
入数据:
出数据:
你会发现,你出数据出的就是1,2,3,我们不需要再导入另外的栈了。
解题思路:
1.我们固定一个入栈的PushST,一个固定的出栈PopST。
2.入数据,只在PushST里入,出数据,我们只在PopST出,当出完时,再把PushST里的数据导入PopST
在这里,我们有了前面的基础,希望大家能够自己去写一下,我们主要来看一下代码:
typedef int STDataType;
typedef struct Stack
{
STDataType* arr;
int top;//记录栈顶
int capacity;
}ST;
//初始化定义
void StackInit(ST* ps)
{
assert(ps);
ps->arr = NULL;
ps->top = 0;
ps->capacity = 0;
}
//销毁函数的定义
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->top = 0;
ps->capacity = 0;
}
//栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//插入函数的定义
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
printf("realloc is fall\n");
exit(-1);
}
else
{
ps->arr = tmp;
ps->capacity = newcapacity;
}
}
ps->arr[ps->top] = x;
ps->top++;
}
//删除函数的定义
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 StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
typedef struct {
ST pushST;
ST popST;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* q=(MyQueue*)malloc(sizeof(MyQueue));
//将两个栈初始化
StackInit(&q->pushST);
StackInit(&q->popST);
return q;
}
void myQueuePush(MyQueue* obj, int x) {
assert(obj);
StackPush(&obj->pushST,x);
}
int myQueuePop(MyQueue* obj) {
assert(obj);
//如果popST为空,把pushST导过来,就符合先进先出的顺序了
if(StackEmpty(&obj->popST))
{
//判断pushST是否为空
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
STDataType front = StackTop(&obj->popST);
StackPop(&obj->popST);
return front;
}
int myQueuePeek(MyQueue* obj) {
assert(obj);
//如果popST为空,把pushST导过来,就符合先进先出的顺序了
if(StackEmpty(&obj->popST))
{
//判断pushST是否为空
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj) {
assert(obj);
return StackEmpty(&obj->pushST)&&StackEmpty(&obj->popST);
}
void myQueueFree(MyQueue* obj) {
assert(obj);
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
free(obj);
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/