数据结构--栈和队列

概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据的插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作被称为进栈/压栈/入栈,入数据的地方为栈顶、

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

出栈、入栈的过程我们可以想象为我们往羽毛球筒里放羽毛球和拿羽毛球,都是只能在一个口进出,是不是可以很形象的想象出来。下面我们来看一看栈是如何实现的。

栈的实现

栈的实现一般可以使用数组或者链表(包括单链表和双向链表)来实现。在使用之前,我们需要考虑哪一种的综合效率最高,从单个节点的空间占用上来看,双向链表是大于单链表和数组的,因此我们首先可以排除双向链表;然后我们来对比一下单链表和数组的优劣:数组在动态开辟空间上可能会有消耗,单链表在开辟空间上较为优良,数组在插入和删除数据上比单链表的操作更为简单,其他区别也都是相差无几,综合下来看,数组和单链表平分秋色,但是在上一章我们了解到了一个缓存利用率的概念,数组的缓存利用率是远大于单链表的,所以我们选择数组作为实现栈的优选。

下面我们先来看一看静态栈的结构:

cpp 复制代码
//实际中一般不使用,所以简单了解
typedef int STDataType;
#define N 10
typedef struct Stack
{
 STDataType _a[N];
 int _top; // 栈顶
}Stack;

支持动态增长的栈的结构:

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int STDataType;

typedef struct StackNode
{
	STDataType* data; //动态开辟数组
	int top; // 栈顶元素的下一个位置
	int capacity; // 容量
}ST;


//创建和销毁
void StackInit(ST* pst);
void StackDestroy(ST* pst);
//入栈和出栈
void StackPush(ST* pst,STDataType x);
void StackPop(ST* pst);
//获取栈顶元素
STDataType StackTop(ST* pst);
//判空
bool StackEmpty(ST* pst);
//求栈中元素个数
int StackSize(ST* pst);

我们来看看相关函数的实现:

cpp 复制代码
//创建和销毁
void StackInit(ST* pst)
{
	assert(pst);
	//初始化
	pst->data = NULL;
	pst->capacity = pst->top = 0;
}
void StackDestroy(ST* pst)
{
	assert(pst);
	free(pst->data);
	free(pst);
}

//在栈的初始化和销毁上,我们要保证指针的有效性,并且在销毁时将数组也一并释放。

//入栈和出栈
void StackPush(ST* pst,STDataType x)
{
	assert(pst);
    //扩容操作我使用了三目操作符,兼顾了多种情况下容量的大小变化。
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 4 : pst->capacity * 2;
        //使用realloc,在容量为0时,realloc == malloc。
		pst->data = (STDataType*)realloc(pst->data,sizeof(STDataType)*newcapacity);
		if (pst->data == NULL)
		{
			perror("malloc fail");
			return;
		}
	}
    //先赋值再后移,因为top是在栈顶元素的下一个位置,当前位置并没有元素。
	pst->data[pst->top] = x;
	pst->top++;
}
//删除函数很简单,不做解释
void StackPop(ST* pst)
{
	assert(pst);

	pst->top--;
}
//获取栈顶元素
STDataType StackTop(ST* pst)
{
	assert(pst);
    //只需一步
	return pst->data[pst->top - 1];
}

//判空
bool StackEmpty(ST* pst)
{
	assert(pst);
    //只需一步
	return (pst->top == 0);
}

//求栈中元素个数
int StackSize(ST* pst)
{
	assert(pst);
    //只需一步
	return pst->top;
}

测试代码各位自行书写,这里不做测试。这里要注意,我们创建的结构体需要传指针参数。

队列

结构及概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)。

入队列:进行插入操作的一端,即队尾。

出队列:进行删除操作的一端,即队头。

队列的实现

队列的结构也可以用数组和链表来实现,因为出队列操作是在数组的头节点上,数组的效率会比较低,所以使用链表的结构实现更好一些。

链式结构表示:

cpp 复制代码
//旧版本
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;
//因为我们在使用单链表时需要同时可以操作队头和队尾,因此我们设置两个指针的QNode结构体,用来便于我们操作链表,在新定义结构体中,我们还加入了size用来计算队列中元素个数。


//优化版本
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

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

头文件包含及函数声明文件:

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	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);

队列函数实现:

cpp 复制代码
//初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = 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, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->next = NULL;
	newnode->val = x;
	//空队列
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
	pq->size++;
}
//出队列
void QueuePop(Queue* pq)
{
	assert(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--;
}
//获取队列的首元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	return pq->phead->val;
}
//获取队列的尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	return pq->ptail->val;
}
//栈空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return (pq->size == 0);
}
//求队列元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

测试及调试操作请各位自行编写。

循环队列

我们假设有k个元素,如果在顺序存储的队列需要建立大于k的数组,并把队列的所有元素存储在数组的前k个单元,数组的首元素就是队头。与栈不同的是,队列元素的出列是在队头,意味着如果我们用数组实现队列的话,队列的所有元素都要向前移动,以保证队列的队头有效性,此时的时间复杂度为O(n)。

循环队列是一种特殊的队列实现方式,我们可以仔细思考,为什么出队列时一定要全部移动呢,如果不去限制队列的元素必须存储到数组的前k个单元,出队的性能就会大大提高。也就是说,我们不需要一定在下标为0的位置去这只队头。

为了避免当只有一个元素时,队头和队尾重合使处理变得麻烦,我们选择队头指针指向队头元素,而队尾指针指向队尾元素的下一个位置,这样当队头等于队尾时,只为空栈;(队尾+1)%(k+1)== 队头时为栈满,如此就解决了假溢出问题。

下面我们来看相关题目:

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为"环形缓冲器"。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

代码实现如下:

cpp 复制代码
typedef struct {
	int* a;
	int phead;
	int ptail;
	int k;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
	MyCircularQueue* pq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	if (pq == NULL)
	{
		perror("malloc fail!");
		return NULL;
	}
	//多开一个数组空间解决假溢出问题
	pq->a = (int*)malloc(sizeof(int) * (k + 1));;
	pq->k = k;
	pq->phead = pq->ptail = 0;
	return pq;
}
//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
	assert(obj);
	return (obj->ptail == obj->phead);
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
	assert(obj);
	return ((obj->ptail + 1) % (obj->k + 1)) == (obj->phead);
}


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

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

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

int myCircularQueueRear(MyCircularQueue* obj) {
	assert(obj);
	if (myCircularQueueIsEmpty(obj))
	{
		return -1;
	}
	else
	{
        //保证了当ptail为0时,不会有减1出现负数的情况。
		return obj->a[(obj->ptail - 1 + obj->k + 1) % (obj->k + 1)];
	}
}


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

经典OJ题目:

有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

1.左括号必须用相同类型的右括号闭合。

2.左括号必须以正确的顺序闭合。

3.每个右括号都有一个对应的相同类型的左括号。

提示:

1 <= s.length <= 10^4,且s 仅由括号 '()[]{}' 组成。

解:

这就是一道经典的栈结构的题目,题中说明只有三种括号,需要我们判断s中的括号是否匹配。我们用栈的结构就可以解决。通过对字符串的数组访问,我们可以遍历整个数组,当遍历道德数组元素为左括号时,元素进栈,当遍历到的数组为右括号时,栈顶元素出栈,与该有括号匹配,如果两括号不匹配,说明字符串中的括号不匹配,如果括号匹配,则继续向后遍历。在遍历中,如果栈为空,而数组中还存在右括号,说明字符串中的括号不匹配;如果遍历结束,而栈不为空,说明字符串中的括号不匹配,否则括号匹配。

代码如下:

cpp 复制代码
//所需头文件
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef char stDataType;
typedef struct Stack
{
	stDataType* data;
	int top;
	int capacity;
}ST;

//栈的初始化
void InitStack(ST* pst)
{
	assert(pst);
	pst->data = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

//销毁栈
void DestroyStack(ST* pst)
{
	assert(pst);

	free(pst->data);
	pst->data = NULL;
	pst->capacity = pst->top = 0;
}

//入栈
void PushStack(ST* pst, stDataType data)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 2 : (pst->capacity * 2);
		stDataType* tmp = (stDataType*)realloc(pst->data, sizeof(stDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("Push malloc fail");
			return;
		}
		else
		{
			pst->data = tmp;
			pst->capacity = newcapacity;
		}
	}
	//尾插
	pst->data[pst->top] = data;
	pst->top++;
}

//出栈
void PopStack(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

	pst->top--;
}

//取栈顶数据
stDataType TopStack(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	//取栈顶元素
	stDataType ret = pst->data[pst->top - 1];
	//返回元素
	return ret;
}

//判断空栈
bool EmptyStack(ST* pst)
{
	assert(pst);
	/*if (pst->top == 0)
	{
		return true;
	}else
	{
		return false;
	}*/
	return (pst->top == 0);
}
//判断是否匹配
bool isValid(char* s) 
{
    ST st;
    InitStack(&st);
    while(*s)
    {
        if(*s == '(' || *s == '{' || *s == '[')
        {
            PushStack(&st,*s);
        }
        else if(*s == ')' || *s == '}' || *s == ']')
        {
            //先判断栈是否为空
            if(EmptyStack(&st))
            {
                DestroyStack(&st);
                return false;
            }
            stDataType tmp = TopStack(&st);
            PopStack(&st);
            if(tmp == '(' && *s != ')'
            || tmp == '{' && *s != '}'
            || tmp == '[' && *s != ']')
            {
                DestroyStack(&st);
                return false;
            }
        }

        ++s;
    }
    //如果栈不为空,说明左括号多于有括号
    bool ret = EmptyStack(&st);
    DestroyStack(&st);
    return ret;
}

用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false

注意:

  • 你只能使用队列的标准操作 ------ 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

提示:

  • 1 <= x <= 9
  • 最多调用100pushpoptopempty
  • 每次调用 poptop 都保证栈不为空

解:

这道题有些难度,但只要把思路捋清楚,结合上面的队列代码就可以简单解决。在这道题中,我们使用了两个队列来完成,栈的特点是后进先出,而队列是先进先出,我们只要利用两个队列来完成后进先出的操作,就可以了。

首先,在myStackCreate函数中我们开辟了自建栈的结构体空间,并利用指针将空间转移给实参。myStackPush函数中,我们需要做的就是检查那个函数不是空队列,然后向不为空队列的队列中继续入元素。myStackPop中首先我们需要判空,因为size不能为负数,接着我们先用假设法设其中一个为空队列,另一个为非空队列,如果不对,我们再讲两个变量转换一下。然后我们将非空队列中的前n-1个数据导入空队列中,再将最后一个数据记录后删除,最后返回该元素的值。剩余函数比较简单,这里不做讲解,各位如果有疑问,可以在评论区讨论。这位额外提一嘴,各位一定要注意断言的使用,我们在插入和删除时数据元素时,不仅要确保指针的有效性,还要确保部分指针头结点的有效性,以及队列为空时,调用删除函数的问题。

cpp 复制代码
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType val;
}QNode;

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


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

//初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = 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, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->next = NULL;
	newnode->val = x;
	//空队列
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
	pq->size++;
}

//求队列元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	if(pq->phead == NULL)
    {
        return;
    }
	//一个节点
	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--;
}
//获取队列的首元素
QDataType QueueFront(Queue* pq)
{
	assert(pq && pq->phead);
	return pq->phead->val;
}
//获取队列的尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq && pq->ptail);
	return pq->ptail->val;
}
//栈空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return (pq->size == 0);
}


MyStack* myStackCreate() 
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    if (pst == NULL) 
    {
        perror("malloc fail");
        return NULL;
    }
    QueueInit(&(pst->q1));
    QueueInit(&(pst->q2));

    return pst;
}

void myStackPush(MyStack* obj, int x) {
    assert(obj);
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&(obj->q1),x);
    }
    else
    {
        QueuePush(&(obj->q2),x);
    }
}

int myStackPop(MyStack* obj) {
   assert(obj);
   Queue* empty = &(obj->q1);
   Queue* noempty = &(obj->q2);
   if(!QueueEmpty(&(obj->q1)))
   {
    empty = &(obj->q2);
    noempty = &(obj->q1);
   }
   //将前n-1个元素移入到另一个队列,删除最后一个元素
    while(QueueSize(noempty) > 1)
    {
        QueuePush(empty,QueueFront(noempty));
        QueuePop(noempty);
    }

    int top = QueueFront(noempty);
    QueuePop(noempty);
    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);
}

用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你只能使用标准的栈操作 ------ 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

提示:

  • 1 <= x <= 9
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

解:

用栈实现队列的思路和用队列实现栈的方式差不多。我们只需要在两个栈中导数据就能够完成,但这次的导数据只需要从一个栈导入另一个栈即可,但是在一次导入之后,如果这个导入之后的栈还有数据,就不能进行第二次导入,这样会导致自建队列的数据顺序改变。在push函数中我们也不需要再调整指针,将qs1作为一栈,qs2作为二栈,每一次push都将数据放入一栈,当需要导入时,就将一栈的数据导入二栈中。

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int STDataType;

typedef struct StackNode
{
	STDataType* data; //动态开辟数组
	int top; // 栈顶元素的下一个位置
	int capacity; // 容量
}ST;

//创建(栈)队列
typedef struct
{
	ST s1;
	ST s2;
}MyQueue;

//创建和销毁
void StackInit(ST* pst)
{
	assert(pst);
	//初始化
	pst->data = NULL;
	pst->capacity = pst->top = 0;
}
void StackDestroy(ST* pst)
{
	assert(pst);
	free(pst->data);
	// 不需要释放 pst 本身,因为它不是动态分配的
	// free(pst);
}
//入栈和出栈
void StackPush(ST* pst, STDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newcapacity = (pst->capacity == 0) ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->data, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("malloc fail");
			return;
		}
		pst->data = tmp;
		pst->capacity = newcapacity;
	}
	pst->data[pst->top] = x;
	pst->top++;
}
void StackPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}
//判空
bool StackEmpty(ST* pst)
{
	assert(pst);
	return (pst->top == 0);
}

//获取栈顶元素
STDataType StackTop(ST* pst)
{
	assert(pst);
	if (!StackEmpty(pst))
		return pst->data[pst->top - 1];
	else
		return -1;
}

//求栈中元素个数
int StackSize(ST* pst)
{
	assert(pst);
	return pst->top;
}


MyQueue* myQueueCreate()
{
	MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
	if (pq == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	StackInit(&(pq->s1));
	StackInit(&(pq->s2));

	return pq;
}

void myQueuePush(MyQueue* obj, int x)
{
	assert(obj);
	StackPush(&(obj->s1), x);

}

int myQueuePop(MyQueue* obj) {
	assert(obj);
	assert(!StackEmpty(&(obj->s1)) || !StackEmpty(&(obj->s2)));
	ST* qs1 = &(obj->s1);
	ST* qs2 = &(obj->s2);
	if (StackEmpty(qs2))
	{
		while (!StackEmpty(&(obj->s1)))
		{
			StackPush(&(obj->s2), StackTop(&(obj->s1)));
			StackPop(&(obj->s1));
		}
	}


	int top = StackTop(&(obj->s2));
	StackPop(&(obj->s2));
	return top;

}
//返回队列开头的元素
int myQueuePeek(MyQueue* obj) {
	assert(obj);
	//同pop函数
	if (StackEmpty(&(obj->s2))) {
		while (!StackEmpty(&(obj->s1))) {
			StackPush(&(obj->s2), StackTop(&(obj->s1)));
			StackPop(&(obj->s1));
		}
	}
	return StackTop(&(obj->s2));
}

bool myQueueEmpty(MyQueue* obj) {
	assert(obj);
	return StackEmpty(&(obj->s1)) && StackEmpty(&(obj->s2));
}

void myQueueFree(MyQueue* obj) {
	assert(obj);
	StackDestroy(&(obj->s1));
	StackDestroy(&(obj->s2));
	free(obj);
}
相关推荐
菜鸡中的奋斗鸡→挣扎鸡6 小时前
滑动窗口 + 算法复习
数据结构·算法
axxy20007 小时前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
Uu_05kkq8 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
1nullptr10 小时前
三次翻转实现数组元素的旋转
数据结构
TT哇10 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
A懿轩A10 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
1 9 J12 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
汝即来归12 小时前
选择排序和冒泡排序;MySQL架构
数据结构·算法·排序算法
aaasssdddd9615 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
芳菲菲其弥章15 小时前
数据结构经典算法总复习(下卷)
数据结构·算法