【数据结构算法经典题目刨析(c语言)】使用队列实现栈(图文详解)

目录

一.题目描述

二.解题思路 

三.代码实现 

💓 博客主页:C-SDN花园GGbond

⏩ 文章专栏:数据结构经典题目刨析(c语言)

 

一.题目描述

二.解题思路 

首先这道题需要我们使用两个队列来完成栈的实现, 这里我们的思路是, 栈的要求是后进先出, 而队列是先进先出, 让两个队列来回导数据, 插入数据时, 插入到不为空的队列中, 如果需要出数据, 先让不为空的队列的前n-1个数据导入到为空的队列中, 然后在出数据, 此时正好就是最后一个数据, 也就是后入先出, 

以下是使用两个队列实现栈的基本步骤和原理: 

栈的结构定义:包含两个队列的结构

1.初始化:初始化两个空队列,在任意时刻,我们只会使用其中一个队列来进行入栈和出栈操作,     而另一个队列则保持为空。
2.入栈(Push):将元素添加到非空队列的末尾。

   如果两个队列都为空,则选择任意一个队列添加元素。
3.出栈(Pop):
  如果两个队列都为空,说明栈也为空,此时不能进行出栈操作。将非空队列中的元素(除了最后    一个)逐个出队并入队到另一个队列中,直到只剩下最后一个元    素。此时,该元素就是栈顶元    素,我们将其出队并返回。

4.查看栈顶元素(Peek):
   如果两个队列都为空,说明栈也为空,此时不能查看栈顶元素。
   如果队列的实现允许查看队尾数据,会比较简单,直接返回非空队列的队尾数据即可
   如果队列实现只允许查看队首数据,那么也需要移动元素
   我们将非空队列的元素(除了最后一个)逐个出队并入队到另一个队列中,直到只剩下最后一个    元素。此时,该元素就是栈顶元素,将其保存下来,入队到另一个队列中,并在本队列出队(这    样做是为了保持只有一个非空队列)然后返回该元素。

这里画图解释队列元素的移动过程(注意:为方便理解对队列的结构进行了简化)  

  

三.代码实现 

步骤如下 

1.因为C语言没有自带的队列, 所以我们需要把我们实现的队列写进去, C++会自带的队列.这里我们直接导入

2.创建MyStack,里面需要两个队列, myStackCreate其实也就是我们的初始化, 这里不可以直接 MyStack s, 因为函数里面的创建的变量出了函数就被释放了 ,所以我们需要动态开辟空间. 分别进行初始化

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* s = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&s->q1);
    QueueInit(&s->q2);
    return s;
}

3.入栈, 哪个不为空, 我们就把元素插入到哪个队列, 这里我使用了假设法, 来找出不为空的队列.

void myStackPush(MyStack* obj, int x) {
     assert(obj);
    //假设法
    Queue* Empty = &obj->q1;
    Queue* nonEmpty = &obj->q2;
    if(QueueEmpty(&obj->q2))
    {
        Empty = &obj->q2;
        nonEmpty = &obj->q1;
    }
    //把数据插入到不为空的队列
    QueuePush(nonEmpty,x);
}

 

4.出栈, 还是假设法, 找到不为空的队列, 然后通过为空的队列导一下,不要忘记找到数据之后, 让最后一个数据出队列.

int myStackPop(MyStack* obj) {
    assert(obj);
    Queue* Empty = &obj->q1;
    Queue* nonEmpty = &obj->q2;
    if(QueueEmpty(&obj->q2))
    {
        Empty = &obj->q2;
        nonEmpty = &obj->q1;
    }
    //把不为空的队列的数据的前n-1个数据导入到为空的队列
    while(QueueSize(nonEmpty)>1)
    {
        QueuePush(Empty,QueueFront(nonEmpty));
        QueuePop(nonEmpty);
    }
    int top = QueueTail(nonEmpty);
    QueuePop(nonEmpty);
    return top;
}

5.剩下的几个方法总体来说比较简单, 代码如下,注意销毁操作, 我们手动开辟的空间都需要手动释放.

int myStackTop(MyStack* obj) {
    assert(obj);
    if(!QueueEmpty(&obj->q1))
    {
        return QueueTail(&obj->q1);
    }
    else{
        return QueueTail(&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);
}

完整代码 


typedef int DataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	DataType val;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;


void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, DataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");//perror函数在<stdio.h>头文件包含,标准错误流
		return;
	}
	newnode->next = NULL;
	newnode->val = x;

	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq!=NULL);//条件为真,程序继续
	assert(pq->size!=0); //条件为真,程序继续

	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

DataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

DataType QueueTail(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* s = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&s->q1);
    QueueInit(&s->q2);
    return s;
}

void myStackPush(MyStack* obj, int x) {
     assert(obj);
    //假设法
    Queue* Empty = &obj->q1;
    Queue* nonEmpty = &obj->q2;
    if(QueueEmpty(&obj->q2))
    {
        Empty = &obj->q2;
        nonEmpty = &obj->q1;
    }
    //把数据插入到不为空的队列
    QueuePush(nonEmpty,x);
}

int myStackPop(MyStack* obj) {
    assert(obj);
    Queue* Empty = &obj->q1;
    Queue* nonEmpty = &obj->q2;
    if(QueueEmpty(&obj->q2))
    {
        Empty = &obj->q2;
        nonEmpty = &obj->q1;
    }
    //把不为空的队列的数据的前n-1个数据导入到为空的队列
    while(QueueSize(nonEmpty)>1)
    {
        QueuePush(Empty,QueueFront(nonEmpty));
        QueuePop(nonEmpty);
    }
    int top = QueueTail(nonEmpty);
    QueuePop(nonEmpty);
    return top;
}

int myStackTop(MyStack* obj) {
    assert(obj);
    if(!QueueEmpty(&obj->q1))
    {
        return QueueTail(&obj->q1);
    }
    else{
        return QueueTail(&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);
*/

 

 

 

 

 

 

 

 

 

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值