栈和队列OJ题合集(包含循环队列的两种实现)

目录

一:前言

二:有效的括号(括号匹配)

三:用队列实现栈

四:用栈实现队列

五:设计循环队列


一:前言

对栈和队列的基本性质和实现有问题的可以看上一期

 链接:http://t.csdn.cn/YQMBA​​​​

 注意:本文用数据的大小来表示入栈入队的先后。

二:有效的括号(括号匹配)

题目链接:https://leetcode.cn/problems/valid-parentheses/

题目要求:

 基础思路:

(1)这个问题实质上就是左右括号的配对。(左括号:'('   ' [ '  ' { ' ; 右括号:' ) '  ' ] '  ' } ')

(2)我们可以从左往右遍历这个字符串,符号为左括号时,我们可以把这个元素压入栈中。如果遇到的元素是右括号,我们就拿出栈中的元素进行匹配,匹配成功就继续遍历不成功就直接返回false,遍历到字符串结束就停止循环

(3)考虑几种特殊情况

①比如"( ( )",这个字符串很明显左右括号没法完全匹配,但它可以进行一次匹配后到空,这个时候我们应该返回false。为了解决这个情况,我们可以设置一个bool类型的变量调用对栈判空的接口,返回这个变量

②比如"( ) )"或者") ) )",这两个字符串的问题是到应该匹配的时候栈为空了,很明显这两个字符串不符号要求,所以我们应该在匹配之前进行栈判空,为空直接返回false

图解:

代码(PS:可以把上一次写的栈复制过来):

//重定义数据类型,方便更改
typedef char STDataType;

typedef struct stack {
	//存储数据
	STDataType* a;
	//栈顶(位置)
	int top;
	//容量
	int capacity;
}ST;

//初始化
void StackInit(ST* ps);

//销毁
void StackDestroy(ST* ps);

//入栈
void StackPush(ST* ps, STDataType x);

//出栈(销毁)
void StackPop(ST* ps);

//取栈顶的数据
STDataType StackTop(ST* ps);

//取栈中的有效数据个数
int StackSize(ST* ps);

//判断栈是否为空
bool StackEmpty(ST* ps);

//初始化
void StackInit(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps );
	//一开始指向NULL
	ps->a = NULL;
	//把栈顶和容量都置为空
	ps->top = ps->capacity = 0;
}

//销毁
void StackDestroy(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps );
	//栈顶和容量置为空
	ps->top = ps->capacity = 0;
	//释放空间
	free(ps->a);
	ps->a = NULL;
}

//入栈
void StackPush(ST* ps, STDataType x)
{
	//断言,不能传空指针进来
	assert(ps);
	//先判断是否扩容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;
		//扩容
		STDataType* tmp = 
		(STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
		//扩容失败
		if (tmp == NULL)
		{
			printf("realloc error\n");
			exit(-1);
		}
		//更新
		ps->capacity = newcapacity;
		ps->a = tmp;
	}
	//存储数据
	ps->a[ps->top] = x;
	ps->top++;
}


//出栈(删除)
void StackPop(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//如果栈为空,不能出栈
	assert(!StackEmpty(ps));
	ps->top--;
}

//取顶部数据
STDataType StackTop(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//如果栈为空,不能进行访问
	assert(!StackEmpty(ps));
	//返回栈顶数据
	return ps->a[ps->top-1];
}

//取栈中的有效数据个数
int StackSize(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//直接返回top
	return ps->top;
}

//判断栈是否为空
bool StackEmpty(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//依据top来判断
	/*if (ps->top == 0)
		return true;
	return false;*/
	//更简洁的写法,一个判断语句的值要么为true,要么false
	return ps->top == 0;
}


bool isValid(char * s){
    ST s1;
    //初始化
    StackInit(&s1);
    while(*s)
    {
        //如果为左括号,入栈
        if(*s=='('||*s=='['||*s=='{')
        {
            StackPush(&s1,*s);
        }
        //如果为右括号,出栈看是否相同
        else
        {
            //如果栈为空,说明没有左括号对应,返回false
            if(StackEmpty(&s1))
            {
                StackDestroy(&s1);
                return false;
            }
            //先记录然后出栈
            STDataType top=StackTop(&s1);
            StackPop(&s1);
            //判断是否可以对应
            if(*s==')'&&top!='('
            ||*s=='}'&&top!='{'
            ||*s==']'&&top!='[')
            {
                //注意销毁栈
                StackDestroy(&s1);
                return false;
            }
        }
        //后移一位
        s++;
    }
    //判断栈是否为空
    bool ret=StackEmpty(&s1);
    //注意销毁栈
    StackDestroy(&s1);
    return ret;
}

三:用队列实现栈

 题目链接:https://leetcode.cn/problems/implement-stack-using-queues/

题目要求:

 基础思路:

(1)我们都知道栈是先进后出而队列是先进先出,这也就代表我们要用队列实现栈的一些操作,基本都是需要反向来的。

(2)为了方便我们出数据和查找数据,我们保持一个队列为空,将栈的数据放在非空队列中。

PS:可以把上一次写的队列复制过来。

栈的结构体和初始化,比较简单,不做过多解析

代码:

void myStackPush( )函数(存储数据)

①比较简单,只需要向非空队列中存储就行。

 myStackPop( )函数(删除数据)

①我们要出栈,实际就是出队列中的队尾元素。

我们需要找到队尾元素,这个操作通过不断出队列,一直到队列只有一个数据(不把队列是否为空设置为循环条件是因为我们要返回栈顶数据)就能实现。

②但我们不想让前面的元素也出栈,就需要将这些元素在出队之前先入到另一个空队列中,这样就可以保证数据不丢失了。

图解:

代码:

 

myStackTop( )函数(返回栈顶数据)

①也比较简单,我们只需要将非空队列的尾部队列元素返回就行。

代码:

 myStackEmpty( )函数(判断是否为空)

①前面我们说只用一个队列存储栈的数据,所以如果两个队列都为空那就代表栈为空

代码:

myStackFree( )函数(销毁)

①需要注意的点就是不要直接释放栈结构体,要先把两个队列释放了

图解:

代码:

 

完整代码:

//重定义,方便更改存储类型
typedef int QDataType;
//结点的结构体
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;
//队列的结构体(头用来开辟链接,尾用来查找)
typedef struct Queue
{
	//头
	QNode* head;
	//尾
	QNode* tail;
}Queue;


//队列的初始化
void QueueInit(Queue* pq);
//入队列(队列只能从后入)
void QueuePush(Queue* pq, QDataType x);
//队列的销毁
void QueueDestroy(Queue* pq);
//出队列(删除)
void QueuePop(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
//查找队列的头数据
QDataType QueueFront(Queue* pq);
//查找队列的尾数据
QDataType QueueBack(Queue* pq);
//查找队列的结点个数
int QueueSize(Queue* pq);

//初始化
void QueueInit(Queue* pq)
{
	//断言,不能传空的结构体指针
	assert(pq);
	//初始化,把头和尾都指向空
	pq->head = pq->tail = NULL;
}

//入队列
void QueuePush(Queue* pq,QDataType x)
{
	//断言,不能传空的结构体指针
	assert(pq);
	//申请新结点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	//如果队列为空,单独处理
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		//原尾指向新结点(链接)
		pq->tail->next = newnode;
		//更新尾
		pq->tail = newnode;
	}
}

//队列销毁
void QueueDestroy(Queue* pq)
{
	//断言,不能传空的结构体指针
	assert(pq);
	//先保存下一个,再释放
	QNode* cur = pq->head;
	while (cur)
	{
		//记录
		QNode* next = cur->next;
		//释放
		free(cur);
		//迭代
		cur = next;
	}
	//头尾都置空
	pq->head = pq->tail = NULL;
}


//出队列(删除)
void QueuePop(Queue* pq)
{
	//断言,不能传空的结构体指针
	assert(pq);
	//断言,队列为空不能删除
	assert(!QueueEmpty(pq));
	//保存原头的下一个结点位置
	QNode* newhead = pq->head->next;
	//释放
	free(pq->head);
	//迭代
	pq->head = newhead;
	//如果删除结束了,要把tail指向空(避免野指针)
	if (pq->head == NULL)
		pq->tail = NULL;
}

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	//断言,不能传空的结构体指针
	assert(pq);
	/*if (pq->head == NULL)
		return true;
	else
		return false;*/
	//依据判断语句的指直接返回
	return pq->head == NULL;
}

//查找队列的头数据
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;
}


//查找队列的结点个数
int QueueSize(Queue* pq)
{
	//断言,不能传空的结构体指针
	assert(pq);
	//计数
	int size = 0;
	//遍历链表
	QNode* cur = pq->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}



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


MyStack* myStackCreate() {
    //自己申请一块空间
    MyStack* st=(MyStack*)malloc(sizeof(MyStack));
    //初始化队列
    QueueInit(&st->q1);
    QueueInit(&st->q2);
    //返回结构体指针
    return st;
}

void myStackPush(MyStack* obj, int x) {
    //如果q1不为空,向q1存储数据,不然向q2存储数据
    if(!QueueEmpty(&obj->q1))
        QueuePush(&obj->q1,x);
    else
        QueuePush(&obj->q2,x);
}

int myStackPop(MyStack* obj) {
    //假设q1为空,q2不为空
    Queue* emptyQ=&obj->q1;
    Queue* nonemptyQ=&obj->q2;
    //如果q1不为空,更改
    if(!QueueEmpty(&obj->q1))
    {
        emptyQ=&obj->q2;
        nonemptyQ=&obj->q1;
    }
    //一直出非空队列的数据并存储到原空队列中,一直到剩余一个数据
    while(QueueSize(nonemptyQ)>1)
    {
        QueuePush(emptyQ,QueueFront(nonemptyQ));
        QueuePop(nonemptyQ);
    }
    //返回栈顶数据
    int top=QueueFront(nonemptyQ);
    //出栈
    QueuePop(nonemptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    //如果q1不为空,返回q1的尾数据,否则返回q2的尾数据
    if(!QueueEmpty(&obj->q1))
        return QueueBack(&obj->q1);
    else
        return QueueBack(&obj->q2);
}

bool myStackEmpty(MyStack* obj) {
    //两个队列同时空就是空,判断语句的值就是true或false
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    //先释放内部的队列,最后释放栈结构体空间
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

四:用栈实现队列

 题目链接:https://leetcode.cn/problems/implement-queue-using-stacks/

 题目要求:

基础思路:

①与前面不同,将一个栈通过取栈顶数据到另一个栈是可以把原栈的数据顺序颠倒的。

②我们可以仿照前面的思路,不过因为移动一次数据的顺序就会颠倒,所以不需要频繁的移动数据,一个栈专门用来存储数据(简称入栈),一个栈专门用来出数据(简称出栈)。

③如果出栈的数据为空,我们需要将入栈的元素补充到出栈中。

图解:

PS:可以把上一次写的栈复制过来。

队列结构体和初始化比较简单,不赘述。

代码:

 myQueuePush( )函数(存储数据)

①很简单,往入栈入数据就行。

代码:

myQueuePop( )函数(删除数据)

如果出栈为空,将入栈的数据移到出栈

先保存要出的数据,然后直接把出栈的栈顶出掉就行。

代码:

  myQueuePeek( )函数(返回队头数据)

①一般来说出栈的栈顶就是队头,但如果出栈为空,我们要将入栈的数据移到出栈

②直接返回出栈的栈顶

代码:

myQueueEmpty( )函数 (判断是否为空)

①如果出栈入栈都为空,队列就为空。

代码:

myQueueFree( )函数(销毁)

①要注意的点和前面类似,不能直接释放队列结构体,要先释放两个栈,然后释放队列结构体。

代码:

完整代码:

//重定义数据类型,方便更改
typedef int STDataType;

typedef struct stack {
	//存储数据
	STDataType* a;
	//栈顶(位置)
	int top;
	//容量
	int capacity;
}ST;

//初始化
void StackInit(ST* ps);

//销毁
void StackDestroy(ST* ps);

//入栈
void StackPush(ST* ps, STDataType x);

//出栈(销毁)
void StackPop(ST* ps);

//取栈顶的数据
STDataType StackTop(ST* ps);

//取栈中的有效数据个数
int StackSize(ST* ps);

//判断栈是否为空
bool StackEmpty(ST* ps);

//初始化
void StackInit(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps );
	//一开始指向NULL
	ps->a = NULL;
	//把栈顶和容量都置为空
	ps->top = ps->capacity = 0;
}

//销毁
void StackDestroy(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps );
	//栈顶和容量置为空
	ps->top = ps->capacity = 0;
	//释放空间
	free(ps->a);
	ps->a = NULL;
}

//入栈
void StackPush(ST* ps, STDataType x)
{
	//断言,不能传空指针进来
	assert(ps);
	//先判断是否扩容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;
		//扩容
		STDataType* tmp = 
		(STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
		//扩容失败
		if (tmp == NULL)
		{
			printf("realloc error\n");
			exit(-1);
		}
		//更新
		ps->capacity = newcapacity;
		ps->a = tmp;
	}
	//存储数据
	ps->a[ps->top] = x;
	ps->top++;
}


//出栈(删除)
void StackPop(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//如果栈为空,不能出栈
	assert(!StackEmpty(ps));
	ps->top--;
}

//取顶部数据
STDataType StackTop(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//如果栈为空,不能进行访问
	assert(!StackEmpty(ps));
	//返回栈顶数据
	return ps->a[ps->top-1];
}

//取栈中的有效数据个数
int StackSize(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//直接返回top
	return ps->top;
}

//判断栈是否为空
bool StackEmpty(ST* ps)
{
	//断言,不能传空指针进来
	assert(ps);
	//依据top来判断
	/*if (ps->top == 0)
		return true;
	return false;*/
	//更简洁的写法,一个判断语句的值要么为true,要么false
	return ps->top == 0;
}

typedef struct {
    //一个入,一个出
    ST PushSt;//出栈
    ST PopSt;//入栈
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* newQueue=(MyQueue*)malloc(sizeof(MyQueue));
    //初始化栈
    StackInit(&newQueue->PushSt);
    StackInit(&newQueue->PopSt);
    return newQueue;
}

void myQueuePush(MyQueue* obj, int x) {
    //入
    StackPush(&obj->PushSt,x);
}

int myQueuePop(MyQueue* obj) {
    //如果要出的那个栈为空,将入栈的元素全部移到出栈中
    if(StackEmpty(&obj->PopSt))
    {
        while(!StackEmpty(&obj->PushSt))
        {
            StackPush(&obj->PopSt,StackTop(&obj->PushSt));
            StackPop(&obj->PushSt);
        }
    }
    //出队列
    int top=StackTop(&obj->PopSt);
    StackPop(&obj->PopSt);
    return top;
}

int myQueuePeek(MyQueue* obj) {
    //如果要出的那个栈为空,将入元素的栈的元素全部移到出栈中
    if(StackEmpty(&obj->PopSt))
    {
        while(!StackEmpty(&obj->PushSt))
        {
            StackPush(&obj->PopSt,StackTop(&obj->PushSt));
            StackPop(&obj->PushSt);
        }
    }
    //返回出栈的top
    return StackTop(&obj->PopSt);
}

bool myQueueEmpty(MyQueue* obj) {
    //两个栈都为空,队列为空,判断语句的值为true或false
    return StackEmpty(&obj->PopSt)&&StackEmpty(&obj->PushSt);
}

void myQueueFree(MyQueue* obj) {
    //先释放栈,再释放队列结构体
    StackDestroy(&obj->PushSt);
    StackDestroy(&obj->PopSt);
    free(obj);
}

五:设计循环队列

题目链接:https://leetcode.cn/problems/design-circular-queue/

题目要求:

思路(解释):

(1)循环队列顾名思义就是一个循环的结构链式结构通过头尾相连来实现循环,

数组结构通过对下标的控制来实现循环,我们看图:

(2)判断队列为空或者满 ,如果我们需要存储多少个数据就开辟多少空间的话,我们可以将头尾相同作为空的条件,但是无法判断满的条件。

我们可以多开辟一个空间将(tail+1)%(存储元素个数+1)==front或者tail->next==front作为判满的条件

图解:

【1】数组结构 

(1)队列结构体定义和初始化

(2)myCircularQueueIsFull( )函数 (判断是否为满)

思路:无非是有一种tail为kfront为0的情况要特殊处理。

其它的全都为tail+1=front

代码:

(3)myCircularQueueIsEmpty( )函数 (判断是否为空)

思路:比较简单,tail与front相等就为空。

代码:

(4)myCircularQueueEnQueue( )函数 (存储数据)

思路:先判断是否为满,满不插入。

不满就插入然后tail+1,如果加1后tail为k,就回到下标0位置

代码:

(5)myCircularQueueDeQueue( )函数 (删除数据)

思路:先判断是否为空,空不删除。

否则就直接front+1,如果front为k,就回到下标0位置

代码:

(6)myCircularQueueFront( )函数(返回队头数据)和myCircularQueueRear( )函数(返回队尾数据

思路:两个函数都比较简单,都要先判断是否为空。

myCircularQueueFront( )直接返回下标front的数据就行。

myCircularQueueRear( )就需要处理一种tail为0的情况,其它情况返回下标为k-1处的数据

代码:

(7)myCircularQueueFree( )函数

最后不要忘记释放空间  

代码:

完整代码:

typedef struct {
    int* a;//存储数据
    int front;//头
    int tail;//尾
    int k;//记录
} MyCircularQueue;

//后面有的接口要用到这两个函数,注意进行函数声明
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);

MyCircularQueue* myCircularQueueCreate(int k) 
{
    //给结构体开空间
    MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //给数组开空间
    q->k=k;
    q->a=(int *)malloc(sizeof(int)*(k+1));
    q->front=q->tail=0;
    return q;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
 {
    //如果满,返回false
    if(myCircularQueueIsFull(obj))
        return false;
    //存储数据,后移一位
    obj->a[obj->tail]=value;
    obj->tail++;
    //如果超出范围,回到下标0位置
    // if(obj->tail==obj->k+1)
    //     obj->tail=0;
    obj->tail%=(obj->k+1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    //如果空,返回false
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->front++;
    //如果超出范围,回到下标0位置
    // if(obj->front==obj->k+1)
    //     obj->front=0;
    obj->front%=(obj->k+1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    //如果空,返回-1
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    //如果空,返回-1
    if(myCircularQueueIsEmpty(obj))
        return -1;
    //也可以用取余的方法找到下标
    // int i=(obj->tail+obj->k)%(obj->k+1);
    // return obj->a[i];
    //如果tail为0,下标k位置为队尾,否则下标tail-1位置为队尾
    if(obj->tail==0)
        return obj->a[obj->k];
    else
        return obj->a[obj->tail-1];
}

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

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    //另外一种
    // if(obj->tail+1==obj->front||(obj->tail==obj->k&&obj->front==0))
    //     return true;
    // else
    //     return false;
    //比较简洁
    return (obj->tail+1)%(obj->k+1)==obj->front;
}

void myCircularQueueFree(MyCircularQueue* obj)
{
    //先释放数组
    free(obj->a);
    //最后释放结构体
    free(obj);
}

【2】链式结构

链式结构的实现只有两个接口需要重点讲一下,其它接口思路和数组结构类似。

(1)结构体和初始化

 

初始化思路:

①我们需要多申请一个空间,并且每一次申请完都要链接起来

②最后要形成循环。 

图解:

代码:

(2)队列的释放

思路:

①先记录头指针的位置,然后让头指针指向下一个结点 。

②利用头指针来就行释放,结束条件为头指针回到原来位置

记得释放掉这个头结点和队列结构体

图解:

代码:

完整代码:

//结点的结构体
typedef struct QueueNode
{
    struct QueueNode* next;
    int data;
}QNode;

typedef struct {
    QNode* head;
    QNode* tail;
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);


MyCircularQueue* myCircularQueueCreate(int k) {
    //申请结构体的空间
    MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //初始化
    q->tail = q->head = (QNode*)malloc(sizeof(QNode));
    //申请空间并链接
    while (k--)
    {
        QNode* newnode = (QNode*)malloc(sizeof(QNode));
        newnode->next = NULL;
        q->tail->next = newnode;
        q->tail = newnode;
    }
    //最后形成循环
    q->tail->next = q->head;
    //把尾指针回归原点
    q->tail = q->head;
    return q;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //如果已经满了,不能入数据
    if (myCircularQueueIsFull(obj))
        return false;
    //存储数据
    obj->tail->data = value;
    obj->tail = obj->tail->next;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //如果为空,不能删除数据
    if (myCircularQueueIsEmpty(obj))
        return false;
    obj->head = obj->head->next;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
     //如果为空,不能查找数据
    if (myCircularQueueIsEmpty(obj))
        return -1;
    return obj->head->data;
}

int myCircularQueueRear(MyCircularQueue* obj) {
     //如果为空,不能查找数据
    if (myCircularQueueIsEmpty(obj))
        return -1;
    //循环,一直到找到tail的前一个结点为止
    QNode* cur = obj->head;
    while (cur->next!=obj->tail)
    {
        cur = cur->next;
    }
    return cur->data;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    //头尾相同为空
    return obj->head == obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    //尾的下一个就是头,为满
    return obj->tail->next == obj->head;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    //先记录头指针,利用头指针释放空间
    QNode* endpoint = obj->head;
    obj->head = obj->head->next;
    while (endpoint != obj->head)
    {
        QNode* freeQ = obj->head;
        obj->head = obj->head->next;
        free(freeQ);
    }
    //最后不要忘记释放原来的头结点
    free(endpoint);
    //释放结构体
    free(obj);
}

​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/5552.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

fastp软件介绍

fastp软件介绍1、软件介绍2、重要参数解析2.1 全部参数2.2 使用示例2.3 重要参数详解(1)UMI去除(2)质量过滤(3)长度过滤(4)低复杂度过滤(5)adapter过滤&#…

《文章复现》考虑用户舒适度的冷热电多能互补综合能源系统优化调度

说明书 免费:https://download.csdn.net/download/qq_50594161/87625438 MATLAB代码:考虑用户舒适度的冷热电多能互补综合能源系统优化调度 关键词:用户舒适度 综合能源 PMV 优化调度 参考文档:《冷热电气多能互补的微能源网鲁…

什么是RabbitMQ?有什么用如何使用?一文回答

RabbitMQ RabbitMQ channel:操作MQ的工具exchange:交换机,路由消息到队列中queue:队列,缓存消息virtual host:虚拟主机,对queue,exchange等资源的逻辑分组 MQ模型 基本消息队列工作…

Java 8 - Lambda 表达式

1. 函数式接口 当一个接口中只有一个非 default 修饰的方法,这个接口就是一个函数式接口用 FunctionalInterface 标注 1)只有一个抽象方法 FunctionalInterface public interface MyInterface {void print(int x); } 2)只有一个抽象方法和…

射频接收机概述

接收机架构 射频接收机架构是指电子设备中用于接收无线电信号的部分。它通常由前置放大器、中频放大器、混频器、局部振荡器和带通滤波器等组成。以下是一个基本的射频接收机架构: 前置放大器:前置放大器的作用是放大接收天线接收到的微弱无线电信号&am…

程序员万万不能去的3种公司,越做越倒退,过来人的经验

俗话说“条条大路通罗马”,但是对于程序员来说,有些路千万别走,走得越久越难以抽身,甚至说毁掉你的职业生涯。 今天来跟大家讲一下,作为程序员,有些公司千万不要进去,你以为稀松平常&#xff0…

用Python发送电子邮件?这也太丝滑了吧(21)

小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 欢迎和猫妹一起,趣味学Python。 今日主题 猫爸赚钱养家,细想起来真的不容易啊! 起早贪黑,都是6点早起做早饭,送…

Autodesk AutoCAD 2023(CAD设计软件)自动化工具介绍以及图文安装教程

Autodesk AutoCAD是一款功能强大的计算机辅助设计软件,主要用于2D和3D设计、制图和草图。它适用于多种行业,包括建筑、土木工程、机械工程、电气工程等等。 Autodesk AutoCAD具有2D和3D设计、多种工具和功能、可扩展性、与其他Autodesk软件集成和多平台…

记录一次解决Maven问题的坑

记录一次解决Maven问题的坑目录概述需求:设计思路实现思路分析1.一步步的解决问题比较方法2.后来感觉和这个没关系3.最后查询资料拓展实现性能参数测试:参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfec…

python get方法及常用的代码

1.首先,我们需要下载一个 Python的 pygame库。 2.接着,我们需要在 Pygame中去注册一个自己的账户。 3.登录成功后,我们就可以去下载 pygame中的文件了。 4.我们现在只需要将下载文件放入到 Pygame库中即可,这就完成了下载&#xf…

算法学习day43

算法学习day431. 力扣1049. 最后一块石头的重量 II1.1 分析1.2 代码2. 力扣494. 目标和2.1 分析2.2 代码3. 力扣474.一和零3.1 分析3.2 代码4.参考资料1. 力扣1049. 最后一块石头的重量 II 1.1 分析 动规五部曲: 1.确定dp数组以及下标的含义 dp[j]表示容量为j的背…

第⑦讲:Ceph集群RGW对象存储核心概念及部署使用

文章目录1.RadosGW对象存储核心概念1.1.什么是RadosGW对象存储1.2.RGW对象存储架构1.3.RGW对象存储的特点1.4.对象存储中Bucket的特性1.4.不同接口类型的对象存储访问对比2.在集群中部署RadosGW对象存储组件2.1.部署RGW组件2.2.集群中部署完RGW组件后观察集群的信息状态2.3.修改…

剑指offer JZ27 二叉树的镜像

Java JZ27 二叉树的镜像 文章目录Java JZ27 二叉树的镜像一、题目描述二、辅助栈三、递归法使用辅助栈和递归法解决剑指offer JZ27 二叉树的镜像的问题。 一、题目描述 操作给定的二叉树,将其变换为源二叉树的镜像。   数据范围:二叉树的节点数 0≤n≤…

--编写一个存储过程,输入一个日期,返回该日期与当下日期的时间差,如果该差是负的,则提示该日期已经过去XX天,不然提示距离该日期还有xx天

--创建存储过程&#xff0c;一个输入参数&#xff0c;一个输出参数 create or replace procedure sp_minus(i_date varchar2,o_minus out varchar2) is --声明一个变量&#xff0c;用来存放异常 v_errm varchar2(200); begin --判断输入格式 if length(i_date)<>8 th…

Redis主从复制

文章目录定义用途怎么使用案例演示三大命令&#xff1a;修改配置文件细节常见方式一主二仆薪火相传反客为主复制原理和工作流程主从复制的缺点定义 主从复制&#xff0c;master以写为主&#xff0c;slave以读为主&#xff0c;当master数据变化的时候&#xff0c;自动将新的数据…

十分钟搞懂Java限流及常见方案

目录限流基本概念QPS和连接数控制传输速率黑白名单分布式环境限流方案常用算法令牌桶算法漏桶算法滑动窗口常用的限流方案Nginx限流中间件限流限流组件合法性验证限流Guawa限流网关层限流从架构维度考虑限流设计限流基本概念 QPS和连接数控制 传输速率 黑白名单 分布式环境…

HTML5 <abbr> 标签 和 HTML5 <applet> 标签

标签定义及使用说明 <abbr> 标签用来表示一个缩写词或者首字母缩略词&#xff0c;如"WWW"或者"NATO"。 通过对缩写词语进行标记&#xff0c;您就能够为浏览器、拼写检查程序、翻译系统以及搜索引擎分度器提供有用的信息。 实例 被标记的缩写词如…

《程序员面试金典(第6版)》面试题 08.04. 幂集(回溯算法,位运算,C++)不断更新

题目描述 幂集。编写一种方法&#xff0c;返回某集合的所有子集。集合中不包含重复的元素。 说明&#xff1a;解集不能包含重复的子集。 示例: 输入&#xff1a; nums [1,2,3] 输出&#xff1a; [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] 解题思路与代码 其实…

博客让谷歌或是百度收录

参考以下大佬的博客教程 Hexo框架(六)&#xff1a;SEO优化及站点被搜索引擎收录设置 | 你真是一个美好的人类 第一步 安装百度和 Google 的站点地图生成插件&#xff1a; npm install hexo-generator-baidu-sitemap --save npm install hexo-generator-sitemap --save 然后来…

文件或目录损坏且无法读取错误的恢复方法

我们在日常的生活当中经常都会遇到各种各样的问题。比如有些时候将磁盘插入电脑之后突然跳出来一个“磁盘结构损坏且无法读取”的提示框&#xff0c;那么像这个情况该怎么解决呢?别着急&#xff0c;小编现在就将磁盘结构损坏且无法读取这个问题的解决方法来分享给你们 文件或目…
最新文章