Use queues to implement stacks (the diagram is super detailed)

introduction

After understanding the knowledge of stacks and queues, we already have a certain understanding of their characteristics: stacks are first-in-last-out, and queues are first-in-first-
out
.

The next two articles will introduce the OJ practice of implementing a stack with two queues and implementing a queue with two stacks:
using a queue to implement a stack OJ link

Implementing a stack with a queue

topic introduction

insert image description here
The title description is very simple:
realize the characteristics of stack storage data through two queues, that is, first in last out:

We need to implement push, pop, top, empty, free:
void push(int x) pushes element x onto the top of the stack;
int pop() removes and returns the top element of the stack;
int top() returns the top element of the stack;
bool empty () Returns true if the stack is empty; otherwise, returns false.

Brief description of ideas

The difficulty of this question is mainly how to pop the elements stored later in the queue, because the characteristic of the queue is first-in-first-out, so the elements at the end of the queue cannot be removed directly.
We can easily think of using the second queue to transfer the elements in the queue to another queue, leaving only one element in the original queue, and the remaining element is the last element entered, just remove this element;
if At this time, if you want to remove the element at the end, move the element in the queue back to the original queue and delete the remaining element; if you
want to insert an element at this time, insert it directly at the end of the queue with the element That's it, just pour it over again when you remove it:

Because, if the elements are removed from the head of the queue in sequence from one queue, and then inserted into another queue in sequence, the order of the data will not change. Therefore, if you want to insert elements at the end, you can insert them directly in the queue with elements; when deleting at the end, you only need to repeatedly invert the data:

insert image description here

accomplish

part of the queue

Before implementing the stack with two queues, we need to implement the interface of the queue, which can be reused directly when implementing the stack. The implementation of the queue will not be repeated here, it has been introduced in detail in the previous article. Here directly copy the various interfaces of the previously implemented queues, including the structure used to define the queue:

typedef int QDataType;

typedef struct QListNode//队列的每个结点
{
    
    
	struct QListNode* pNext;
	QDataType data;
}QNode;

typedef struct Queue// 队列的结构
{
    
    
	QNode* front;
	QNode* rear;
	int size;
}Queue;

// 队列的部分
// 初始化队列
void QueueInit(Queue* pq)
{
    
    
	assert(pq);
	pq->front = NULL;
	pq->rear = NULL;
	pq->size = 0;
}
// 检测队列是否为空,如果为空返回非0,非空返回0
int QueueEmpty(Queue* pq)
{
    
    
	assert(pq);
	return pq->front == NULL;
}
// 队尾入队列
void QueuePush(Queue* pq, QDataType data)
{
    
    
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);
	newnode->data = data;
	newnode->pNext = NULL;
	if (QueueEmpty(pq))
	{
    
    
		pq->front = newnode;
		pq->rear = newnode;
	}
	else
	{
    
    
		pq->rear->pNext = newnode;
		pq->rear = newnode;
	}
	pq->size++;
}
// 队头出队列
void QueuePop(Queue* pq)
{
    
    
	assert(pq && QueueEmpty(pq)==0);
	QNode* cur = pq->front->pNext;
	if (cur)
	{
    
    
		free(pq->front);
		pq->front = cur;
	}
	else
	{
    
    
		free(pq->front);
		pq->front = NULL;
		pq->rear = NULL;
	}
	pq->size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* pq)
{
    
    
	assert(pq && QueueEmpty(pq)==0);
	return pq->front->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* pq)
{
    
    
	assert(pq && QueueEmpty(pq)==0);
	return pq->rear->data;
}
// 销毁队列
void QueueDestroy(Queue* pq)
{
    
    
	assert(pq);
	QNode* cur = pq->front;
	QNode* next = pq->front;
	while (cur)
	{
    
    
		next = cur->pNext;
		free(cur);
		cur = next;
	}
	pq->front = NULL;
	pq->rear = NULL;
	pq->size = 0;
}

part of the stack

With the implementation of the queue, we need to create two queues q1 and q2, and store these two queues in a structure variable for easy access:

typedef struct //两个队列
{
    
    
	Queue q1;
	Queue q2;
} MyStack;

stack creation

For this interface, the title does not give parameters. We just dynamically open up a space for the structure MyStack and initialize it.
When initializing, we can directly reuse the queue initialization function QueueInit to initialize two queues:

//创建栈
MyStack* myStackCreate() 
{
    
    
	MyStack* pmst = (MyStack*)malloc(sizeof(MyStack));
	assert(pmst);
	QueueInit(&pmst->q1);
	QueueInit(&pmst->q2);
	return pmst;
}

Check if the stack is empty

The stack is empty, i.e. both queues are empty.
So we directly reuse the function QueueEmpty to judge whether the queue is empty. When both queues are empty, that is, when the return values ​​of both functions are true, it returns true, otherwise it returns false:

//判断栈是否为空为空返回1,非空返回0
bool myStackEmpty(MyStack* obj)
{
    
    
	assert(obj);
	if (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2))//当两个队列全为空时才为空
	{
    
    
		return 1;
	}
	else
	{
    
    
		return 0;
	}
}

Push the stack

When pushing the stack, we need to insert elements into the queue that is not empty. If they are all empty, just insert one at random: when inserting
insert image description here
, we can directly reuse the queue insertion function QueuePush:

//从栈顶入栈
void myStackPush(MyStack* obj, int x) 
{
    
    
	assert(obj);
	if (QueueEmpty(&obj->q1)==0)//在有数据的那个队列入栈
	{
    
    
        assert(QueueEmpty(&obj->q2));
		QueuePush(&obj->q1, x);
	}
	else
	{
    
    
        assert(QueueEmpty(&obj->q1));
		QueuePush(&obj->q2, x);
	}
}

pop out

When popping the stack, we need to transfer the elements in the queue with elements to the empty queue until there is one element left. Just remove this element:
insert image description here
when transferring elements, we can reuse the QueueFront function to take out the elements at the head of the queue, and then use QueuePush to insert them at the end of another queue. Then QueuePop, delete the first element in the original queue:

//从栈顶出栈
int myStackPop(MyStack* obj) 
{
    
    
	assert(obj && myStackEmpty(obj)==0);
	QDataType ret = 0;
	//将有数据的那个队列转移到空队列中,返回剩下的那个数据
	if(QueueEmpty(&obj->q1)==0 && QueueEmpty(&obj->q2))
	{
    
    
		while (obj->q1.size > 1)
		{
    
    
			QueuePush(&obj->q2, QueueFront(&obj->q1));
			QueuePop(&obj->q1);
		}
		ret = QueueFront(&obj->q1);
		QueuePop(&obj->q1);
	}
	else if (QueueEmpty(&obj->q2)==0 && QueueEmpty(&obj->q1))
	{
    
    
		while (obj->q2.size > 1)
		{
    
    
			QueuePush(&obj->q1, QueueFront(&obj->q2));
			QueuePop(&obj->q2);
		}
		ret = QueueFront(&obj->q2);
		QueuePop(&obj->q2);
	}
	else
	{
    
    
		return EOF;
	}
	return ret;
}

Access the top element of the stack

When accessing the top element of the stack, it is enough to access the tail element of the queue with elements.
We can directly reuse the QueueBack function that accesses the tail element of the queue:

//访问栈顶元素
int myStackTop(MyStack* obj) 
{
    
    
	assert(obj && myStackEmpty(obj) == 0);
	QDataType ret = 0;
	if (QueueEmpty(&obj->q1) == 0 && QueueEmpty(&obj->q2))//访问有数据的那个队列的尾数据
	{
    
    
		ret = QueueBack(&obj->q1);
	}
	else if (QueueEmpty(&obj->q2) == 0 && QueueEmpty(&obj->q1))
	{
    
    
		ret = QueueBack(&obj->q2);
	}
	else
	{
    
    
		return EOF;
	}
	return ret;
}

stack release

When releasing the stack, directly reuse the queue release function QueueDestroy to release two queues respectively. Finally, just release the dynamically created structure variable:

//释放栈
void myStackFree(MyStack* obj) 
{
    
    
	QueueDestroy(&obj->q1);
	QueueDestroy(&obj->q2);
	free(obj);
}

Summarize

So far, the topic of using two queues to realize the stack is finished. In the next article, we will introduce the use of two stacks to realize the queue. Welcome everyone to continue to pay attention.

If you think that I did not introduce a certain part clearly or that there is a problem with a certain part, you are welcome to raise it in the comment area

If this article is helpful to you, I hope it will be connected with one click

Hope to make progress together with you

Guess you like

Origin blog.csdn.net/weixin_73450183/article/details/129740552