文章目录
- 前言
- 使用两个队列实现栈
- 1.队列接口函数引入
- 2.栈的初始化
- 3.向栈中插入元素
- 4.出栈操作
- 5.取出栈顶元素
- 6.判断栈是否为空
- 7.释放内存空间
- 总结
前言
本文章主要介绍栈和队列的相互转换。
使用两个队列实现栈
我们知道,栈的特点是后进先出,而队列的特点是先进先出。
栈的特点:
队列的特点:
使用两个队列实现栈的思路是:
1.向两个队列中的任一队列放入元素
2.取出元素时,队列的功能是先进先出,要达到后进先出,需要将前面的所有元素取出,存入另一个空队列中,然后将剩下的最后一个元素释放掉即可。
比如:
后面如果想继续插入元素的话,应该将插入的元素放在非空队列中,这样就实现了栈的功能。
这样实现的原因是,两个队列中必有其中一个队列是空队列,保证了栈的后进先出的特点。
下面给出一道题目
两个队列实现栈
这里我用c语言来实现,所以先先写好队列的基本功能,再将接口函数引入。
1.队列接口函数引入
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
//del = NULL;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (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(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* del = pq->head;
pq->head = pq->head->next;
free(del);
}
pq->size--;
}
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;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;
}
// 1G = 1024MB
// 1024MB = 1024*1024KB
// 1024*1024KB = 1024*1024*1024Byte
int QueueSize(Queue* pq)
{
assert(pq);
/*int size = 0;
QNode* cur = pq->head;
while (cur)
{
cur = cur->next;
++size;
}
return size;*/
return pq->size;
}
2.栈的初始化
MyStack* myStackCreate() {
MyStack*st = (MyStack*)malloc(sizeof(MyStack));
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
栈的初始化就是将两个队列进行初始化。
3.向栈中插入元素
保证其中一个队列不为空
//首先需要判断哪个队列为空,可以用ifelse来判断,但是这样操作冗余的,所以可以使用假设
int myStackPop(MyStack*
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
由于无法得知哪一个队列为空,则需要判断或者假设,使用判断的化,代码比较冗余,在这里我使用假设,假设第一个队列是空。
4.出栈操作
int myStackPop(MyStack* obj) {
Queue*EmptyQ = &obj->q1;
Queue*NonEmptyQ = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
//如果q1不为空,返回假,!就返回真,进入if
//意思就是我们假设错误了。
EmptyQ = &obj->q2;
NonEmptyQ = &obj->q1;
}
//来到这里已经知道哪个是空了,把所有元素导入非空队列,将最后一个不导
while(QueueSize(NonEmptyQ)>1)
{
QueuePush(EmptyQ,QueueFront(NonEmptyQ));
QueuePop(NonEmptyQ);
}
int top = QueueFront(NonEmptyQ);
QueuePop(NonEmptyQ);
return top;
}
5.取出栈顶元素
int myStackTop(MyStack* obj) {
//取出栈顶元素
//在首先的队列中,我们虽然不能删除队尾元素,但是我们可以取出队尾的元素
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
6.判断栈是否为空
bool myStackEmpty(MyStack* obj)
{
//判断栈是否为空,需要判断两个队列是否为空
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
判断栈是否为空,需要判断两个队列是否为空
7.释放内存空间
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
注意,由于两个队列的维护是依靠指针,所以两个队列申请的空间先释放,再释放栈结构体空间
总结
本文章介绍了两个队列实现栈的方法。
使用队列实现栈和使用栈实现队列都是可以的
下篇文章介绍使用两个栈实现队列