栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列

这篇具有很好参考价值的文章主要介绍了栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

队列的实现

这里的队列我们使用链式队列,好处就是可以很方便的取出队头的元素。
使用顺序队列取出队头元素所花费的时间复杂度为O(N),把后面的元素向前移动一个下标所花费的时间。
链式队列的存储结构:

栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列

typedef int QueueDataType;
//节点类型
typedef struct QueueNode
{
	QueueDataType data;
	struct QueueNode* next;
}QNode;
//队列类型
typedef struct Queue
{
	QNode* phead;  //头指针
	QNode* ptail;  //尾指针   使用头指针和尾指针来实现队列的删除和插入操作。
	int size;
}Que;

接口函数的实现
`

void QueueInit(Que* pq);
void QueueDestory(Que* pq);
void QueuePush(Que* pq, QueueDataType x);
void QueuePop(Que* pq);
QueueDataType QueueFront(Que* pq);
QueueDataType QueueBack(Que* pq);
int QueueSize(Que* pq);
bool QueueEmpty(Que* pq);

//实现

//初始化队列
void QueueInit(Que* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

//销毁队列,这里相当于单链表的销毁,一个节点一个节点销毁
void QueueDestory(Que* pq)
{
	assert(pq);
	//删除链式队列
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
}

//相当于单链表的尾插,先新建一个节点,初始化这个节点,尾插到队列中,这里考虑两种情况,队列为空和不为空的情况
void QueuePush(Que* pq, QueueDataType x)
{
	assert(pq);
	//新建节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc failed!\n");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	//考虑此时的队列为空
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		//不为空时,把newnode赋值给phead->next,然后ptail = newnode
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
//相当于单链表的头删。需要考虑两种情况,队列为空就不可以删除,队列不为空只有一个节点phead和ptail都要赋值成NULL,否则会出现ptail为野指针的情况,多个节点时,相当于单链表的头删,
void QueuePop(Que* pq)
{
	//相当于单链表的头删
	assert(pq);
	//处理队列为空的情况
	assert(!QueueEmpty(pq));
	//处理只有一个节点的情况
	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--;
}
QueueDataType QueueFront(Que* pq)
{
	assert(pq);
	//处理队列为空的情况
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
//返回队列的尾部元素,这里会在用队列实现栈的时候用到
QueueDataType QueueBack(Que* pq)
{
	assert(pq);
	//处理队列为空的情况
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}
int QueueSize(Que* pq)
{
	assert(pq);
	return pq->size;
}
bool QueueEmpty(Que* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
	//return pq->size == 0;
}

用队列实现栈

leetcode做题链接栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列

主要思想:用两个队列来实现一个栈的功能,先进后出,后进先出的功能,我们可以这样,在不为空的队列里入数据,然后再把数据前n-1个数数据倒入另一个队列中,具体的过程用图展示:

第一步:准备两个队列,开始入数据
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第二步:往不为空的队列里入数据,如果两个都为空,任选一个入数据
push 四次。可得队列中的数据如下图所示:
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第三步:出数据,需要先把q1中的数据1、2、3倒入q2中,然后使用QueueBack()接口获取队尾数据4。
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
以上就是出数据和入数据的过程。
具体代码如下:

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


MyStack* myStackCreate() {
   MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
   if(obj == NULL)
   {
       perror("malloc failed!\n");
       return NULL;
   }
   QueueInit(&obj->q1);
   QueueInit(&obj->q2);

   return obj;
}

void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);   //入数据,往不为空的队列里如数据
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) {
    //假设为空
    Que* pEmptyQ = &obj->q1;
    Que* pNonEmptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        pEmptyQ = &obj->q2;
        pNonEmptyQ = &obj->q1;
    }
    //倒数据,把非空队列的数据导入空队列,剩余一个就是栈顶元素
    while(QueueSize(pNonEmptyQ)>1)
    {
        QueuePush(pEmptyQ, QueueFront(pNonEmptyQ));
        QueuePop(pNonEmptyQ);
    }
    int top = QueueFront(pNonEmptyQ);
    QueuePop(pNonEmptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

用栈实现队列

leetcode 做题链接
基本思想
使用两个栈,一个为入数据的栈,一个为出数据的栈,把数据入到入数据的栈,然后出数据到出数据的栈,基本方法如下:入队列1 2 3 4。
第一步:初始化两个栈。
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第二步:入数据push 1 2 3 4
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第三步:导数据到popst中
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第四步:从popst中出数据
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
实现代码如下:

typedef struct {
    ST pushst;
    ST popst;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("malloc failed!\n");
        return NULL;
    }
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    STPush(&obj->pushst,x);
}

int myQueuePop(MyQueue* obj) {
    int front = myQueuePeek(obj);
    STPop(&obj->popst);
    return front;
}

int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&obj->popst))
    {
        while(!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst,STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    return STTop(&obj->popst);
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}

void myQueueFree(MyQueue* obj) {
    STDestory(&obj->pushst);
    STDestory(&obj->popst);
    free(obj);
}

设计循环队列

leetcode做题链接
循环队列的要点:如何用一个顺序表实现一个循环队列,front为队头,rear为队尾,判满:rear + 1 == front为满,判空:rear == front 为空。
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第一步,初始化一个队列,k为5,n为6
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
第二步:出队列 front++;再入数据 6、7。
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
此时的rear,跑到了front的前面,我们可以 让rear % (k+1)保持rear永远不会越界front也可以使用这个公式保证front永远不会越界
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列
获取队尾元素的两种方法:
栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列

求元素的个数的方法: (rear - front + k+1)% (k+1)

具体的实现代码如下:

typedef struct {
    int front;
    int rear;
    int k;
    int* a;
} MyCircularQueue;


bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1) == obj->front;
}
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if(obj == NULL)
    {
        perror("malloc failed!\n");
        return NULL;
    }
    obj->a = (int*)malloc(sizeof(int)*(k+1));
    if(obj->a == NULL)
    {
        perror("malloc failed!\n");
        return NULL;
    }
    obj->front = obj->rear = 0;
    obj->k = k;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear] = value;
    obj->rear++;
    obj->rear %= (obj->k+1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front%=(obj->k+1);
    return true; 
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];

}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    //return obj->a[(obj->rear+obj->k)%(obj->k+1)];
    if(obj->rear==0)
    {
        return obj->a[obj->k];
    }
    else
    {
        return obj->a[obj->rear-1];
    }
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

好的我们下一篇再见。文章来源地址https://www.toymoban.com/news/detail-512164.html

到了这里,关于栈和队列(二) 队列的实现,用栈实现队列,用队列实现栈,设计循环队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第10天-代码随想录刷题训练-第五章 栈和队列- ● 理论基础 ● 232.用栈实现队列 ● 225. 用队列实现栈

    栈和队列对应的三个不同的STL版本,底层实现方式不一样, 为我们所知道的是 SGI STL 栈 栈提供 pop和push等接口, 不提供走访功能 也不提供迭代器, 不像map和set可以使用迭代器遍历,往往不被归类为容器,而是容器适配器 栈的内部实现结构可以使用 verctor、list 和 deque(默认)

    2024年02月04日
    浏览(29)
  • 【数据结构】队列篇| 超清晰图解和详解:循环队列模拟、用栈实现队列、用队列实现栈

    博主简介: 努力学习的22级计算机科学与技术本科生一枚🌸 博主主页: @是瑶瑶子啦 每日一言🌼: 每一个不曾起舞的日子,都是对生命的辜负。——尼采 🔗622. 设计循环队列 👧🏻 思路: 🍊数据结构: 使用数组为数据结构,且采用牺牲一个空间的方法来包装判空和判满的

    2024年02月11日
    浏览(29)
  • 栈和队列OJ题合集(包含循环队列的两种实现)

    目录 一:前言 二:有效的括号(括号匹配) 三:用队列实现栈 四:用栈实现队列 五:设计循环队列 对栈和队列的 基本性质和实现 有问题的可以看上一期  链接: http://t.csdn.cn/YQMBA​​​​  注意:本文用数据的大小来表示入栈入队的先后。 题目链接:https://leetcode.cn/problems/valid-paren

    2023年04月15日
    浏览(22)
  • 关于用栈和队列分别解决走迷宫问题的方法讨论(参与者:陈卓,毛敏磊)

    对于生活中最常见的小游戏——走迷宫,相信大家都不陌生,人为走相信大家都会走,但能不能用代码实现,我们认为是可以的,以下是我们对如何走迷宫的一些看法和代码实现(cz负责队列解决,mml负责用栈解决) 先简单介绍一下 队列 :队列是一种操作受限的线性表,只

    2024年04月08日
    浏览(71)
  • 第 3 章 栈和队列 (循环队列)

    1. 背景说明 和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外, 尚需附设两个指针 front 和 rear 分别指示队列头元素及队列尾元素的位置。约定:初始化建空队列时,令 fronts = rear = 0, 每当插入新的队列尾元素

    2024年02月10日
    浏览(24)
  • 数据结构:循环队列的实现(leetcode622.设计循环队列)

      目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口  3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览  三.静态单向循环链表实现循环队列  1.链表循环队列的结构设计 2.创建静态

    2024年02月03日
    浏览(27)
  • 【用队列实现栈】【用栈实现队列】Leetcode 232 225

    ---------------🎈🎈题目链接 用队列实现栈🎈🎈------------------- ---------------🎈🎈题目链接 用栈实现队列🎈🎈-------------------

    2024年01月20日
    浏览(36)
  • 【leetcode】232. 用栈实现队列

    1.使用两个栈结构构建队列 我们需要自定义栈及其相关操作 栈结构遵循后入先出的原则,队列结构遵循先入先出的原则 构建具有两个栈结构的队列,栈pushST用于数据的插入,栈popST用于数据的删除 为栈结构动态开辟空间并初始化栈结构 2.入队操作 模拟入队操作,即将所有元

    2024年02月12日
    浏览(30)
  • leetcode 232.用栈实现队列

    🌟 leetcode链接:用栈实现队列 1️⃣ 思路和图解: push: pop: peek: 和 pop 类似。 代码: ✨ 栈和队列相关接口代码(可复制): 【数据结构】栈和队列

    2024年02月13日
    浏览(30)
  • 【数据结构】用栈实现队列

    前言:本节博客分享了用栈实现队列效果的思路以及代码,有需要借鉴即可。 LINK 如果要用栈实现队列,我们直到栈是先入后出的一个效果,所以我们可以用两个栈,这样逆转两次数不就是入栈之前数组的顺序嘛。下面是一些图辅助理解: 完。

    2024年03月10日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包