数据结构(栈和队列的实现)

news2024/10/4 7:03:18

1. 栈(Stack)

1.1 栈的概念与结构

  • 栈是一种特殊的线性表,其只允许固定的一段插入和删除操作;进行数据插入和删除的一段叫做栈顶,另一端叫栈底;栈中的元素符合后进先出LIFO(Last In First Out)的原则。
  • 入栈:入栈就是往栈里放入数据;
  • 出栈:出栈就是从栈里拿出数据;(注意这两个操作都是对栈顶的数据进行操作);

2be032cadfd94a079a2bf58337718e8d.png

  • 栈底层结构选型:栈的实现选用的是数组;选用链表也可以,但在插入和删除操作更方便一些;因为链表尾插需要遍历找到尾结点,那么尾插的操作时间复杂度就为O(N),不过我们可以优化一下,拿链表的头部作为栈顶,插入和删除就为O(1)了,但是由于我们可能还需要创建多个指针进行操作,所以最优还是选择数组,因为数据的尾插和尾删时间复杂度都为O(1),而且找到尾部的位置不需要创建什么指针啥的,因为顺序表里本身就有一个size代表数组的大小,而最后一个位置则是下标为size-1的位置;

1.2 栈的实现

       --定义栈的模型

        由于栈底层可以使用顺序表实现,那就和之前顺序表一样,需要一个计算总空间有多大的capacity和一个储存有效元素个数的top(在顺序表其实就是size,但这里为了符合栈所以用top),还有一个储存整型类型的数组,但后面会出现增容的操作所以使用指针,STDateType* arr;如下代码所示:

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int STDatetype;

typedef struct Stack
{
	STDatetype* arr;
	int capacity;  //栈空间大小
	int top;       //栈顶
}ST;

        --栈的初始化和销毁

void STInit(ST* st)
{
	assert(st);
	st->arr = NULL;
	st->capacity = st->top = 0;
}

void STDestory(ST* st)
{
	assert(st);
	if(st->arr)
		free(st->arr);
	st->arr = NULL;
	st->capacity = st->top = 0;
}

        --入栈操作的实现

        入栈的实现:首先我们要判空间是否足够,而判断空间是否足够的条件就是栈顶是不是等于整个数组空间的容量,如果等于就需要使用realloc进行扩容,那么我们就需要创建一个Newcapacity作为扩容的空间,我们按2倍进行扩容则:2* capacity, 但是如果说capacity为0的话那么就无法进行扩容,因为0 * 任何数都等于0,所以我们写一个三目运算符,如果说capacity等于0的话就让Newcapacity等于4,否则等于2* capacity;后面我们就需要创建一个新的指针指向扩容的空间,因为如果说扩容失败的话就会对整块空间造成影响,所以我们需要创建一个新的空间进行扩容;而入栈的实现其实就是在数组最后面插入元素;代码实现如下:

void StackPush(ST* ps, STDatetype x)
{
	assert(ps);
	if (ps->capacity == ps->top  )
	{
		int Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDatetype* temp = (STDatetype*)realloc(ps->arr, Newcapacity *sizeof(STDatetype) );
		if (temp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = Newcapacity;
	}
	ps->arr[ps->top++] = x;
}

      

          --判断栈是否为空

        判空实现:其实就是看看栈顶是否为0,当栈顶都为0,那肯定就是没有数据了;代码实现如下:

bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

        --出栈操作的实现

        出栈的实现:实际上其实就是顺序表进行尾删操作,那我们就直接让数组内的有效元素减少一个就可以,即size--;但是我们还需要判断栈是否为空,如果为空那就没有元素可以出;代码如下:

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	--ps->top;
}

        --取栈顶元素

        取栈顶元素:取栈顶元素则是直接返回数组的尾部元素即是:ps->arr[ps->top-1];为什么要-1?因为top是有效元素的个数,但下标的起始位置是0,所以要-1;如下代码所示:

//取栈顶元素
STDatetype StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	
	return ps->arr[ps->top-1];
}

        --获得栈中有效元素的个数

        由上可知,有效元素的个数其实就是top,所以直接返回即可;如下代码所示:

//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

1.3 栈的完整代码

Stack.h

#pragma once

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int STDatetype;

typedef struct Stack
{
	STDatetype* arr;
	int capacity;  //栈空间大小
	int top;       //栈顶
}ST;

//首先创建这些都是要实现初始化
void STInit(ST* st);
void STDestory(ST* st);

//栈顶---入数据、出数据
void StackPush(ST* ps, STDatetype x);
void StackPop(ST* ps);

//取栈顶元素
STDatetype StackTop(ST* ps);

bool StackEmpty(ST* ps);

//获取栈中有效元素个数
int STSize(ST* ps);

Stack.cpp

#include"Stack.h"

void STInit(ST* st)
{
	assert(st);
	st->arr = NULL;
	st->capacity = st->top = 0;
}
void STDestory(ST* st)
{
	assert(st);
	if(st->arr)
		free(st->arr);
	st->arr = NULL;
	st->capacity = st->top = 0;
}

void StackPush(ST* ps, STDatetype x)
{
	assert(ps);
	if (ps->capacity == ps->top  )
	{
		int Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDatetype* temp = (STDatetype*)realloc(ps->arr, Newcapacity *sizeof(STDatetype) );
		if (temp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = Newcapacity;
	}
	ps->arr[ps->top++] = x;
}

bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	--ps->top;
}

//取栈顶元素
STDatetype StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	
	return ps->arr[ps->top-1];
}

//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

 

2. 队列(Queue)

2.1 队列的概念与结构

  • 概念:只允许在一端插入数据和从另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out);
  • 入队列:进行插入操作的一端称为队尾;
  • 出队列:进行删除操作的一端称为队头;3752428e35374bd0b144a601c3255fd0.png
  • 队列的底层结构选型:队列底层结构选的是链表,因为要进行入队列和出队列的操作,如果说用顺序表的话,在进行出队列的操作的时候删除了头部数据那就得让后面数据往前走,那时间复杂度就为O(N),所以我们使用链表;但使用链表的时候要注意,我们需要头结点出数据实现出队列操作,尾结点入数据实现入队列操作,不然的话我们要遍历到尾结点删除数据实现出队列 时间复杂度又为O(N)了;

2.2 队列的实现

        --定义队列的模型

        队列的底层实现就是用链表来实现,那么我们就要定义结点还有队列的模型;为什么要定义两个呢?因为我们还需要一个指向头结点和指向尾结点的指针,还有一个整型size记录队列内的数据;

#pragma once
#include<iostream>
#include<stdlib.h>
#include<assert.h>
using namespace std;


typedef int QDataType;
//每个结点
typedef struct QueueNode
{
	QDataType data;
	QueueNode* next;
}QueueNode;

//队列
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* tail;
	int size;
}Queue;

        --队列的初始化和销毁

        队列的销毁其实就和链表的销毁一样,首先创建一个指向头结点下一个节点的next指针,然后把头结点销毁掉,在让头结点指针指向next指针,next指针再走向头结点的下一个指针,一直循环到头结点为NULL的时候结束‘;代码如下:

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


void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->tail = NULL;
	pq->size = 0;
}

        --入队列的实现

        入队列的实现:需要结合链表的buynode(动态申请一个结点空间)来实现,首先我们先申请一个newnode的空间,让其指向空,data = x;再就要判断队列是否为空,如果说队列为空的话那就说明队列里面没有结点,那就需要让phead和ptail指针指向该结点,如果有结点的话就让ptail->next指针指向newnode,再让ptail走到newnode的位置,最后还要记得size++,因为size是计算队列内有效元素的个数;如下图和代码所示:

队列为空:c37f4e64bb334c14b62a998189b9f5f7.gif

队列不为空:0e56d732009c4c888509b140233e66ba.gif

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	//说明链表为空
	if (pq->phead == NULL)
	{
		pq->phead = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = pq->tail->next;
	}
	pq->size++;
}

        --队列判空操作

        队列判空其实就是看头结点和尾结点的指针是否都指向NULL,如果都指向NULL就为空;代码如下:

//队列判空
bool QueueEmpty(Queue* pq)
{
	return pq->phead == NULL && pq->tail == NULL;
}

        --出队列的操作

        出队列的操作本质上就是链表删除头结点;我们只需要定义一个Del指针指向当前的头结点pcur,再让当前的头结点走到头结点的下一个结点pcur = pcur->next,然后free掉Del结点即可;图和代码如下:7ddc014d159a4d6dbcd5ae0c1584edb9.gif

// 出队列,队头
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	//只有一个结点
	if (pq->tail == pq->phead)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->tail = NULL;
	}
	else
	{
		QueueNode* Del = pq->phead;
		pq->phead = pq->phead->next;
		free(Del);
	}
	--pq->size;
}

注意!!!我们还需要单独判断只有一个结点的时候,当ptail和phead都指向同一个空间的时候就代表队列中只有一个结点,那么这时候我们还进行phead = phead->next就是让phead走向一块未知的空间,进行非法访问;


        --取队头和队尾数据

        因为有指针指向队头和队尾,就不过多阐述了;注意一点就是我们要判断队列是否为空;代码如下所示:

//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

        --取队列有效元素个数

        因为我们一开始就已经创建了一个size 对队列的有效元素个数进行记录,所以直接返回size即可;如下代码所示:

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

2.3 队列的完整代码

Queue.h

#pragma once
#include<iostream>
#include<stdlib.h>
#include<assert.h>
using namespace std;


typedef int QDataType;
//每个结点
typedef struct QueueNode
{
	QDataType data;
	QueueNode* next;
}QueueNode;

//队列
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* tail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
// 出队列,队头
void QueuePop(Queue* pq);

//队列判空
bool QueueEmpty(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);
//队列有效元素个数
int QueueSize(Queue* pq);

//销毁队列
void QueueDestroy(Queue* pq);

Queue.cpp

#include"Queue.h"


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

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	//说明链表为空
	if (pq->phead == NULL)
	{
		pq->phead = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = pq->tail->next;
	}
	pq->size++;
}

//队列判空
bool QueueEmpty(Queue* pq)
{
	return pq->phead == NULL && pq->tail == NULL;
}

// 出队列,队头
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	//只有一个结点
	if (pq->tail == pq->phead)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->tail = NULL;
	}
	else
	{
		QueueNode* Del = pq->phead;
		pq->phead = pq->phead->next;
		free(Del);
	}
	--pq->size;
}


//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}
//队列有效元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->tail = NULL;
	pq->size = 0;
}

3.栈和队列的OJ题

3.1 有效的括号

原题链接:20. 有效的括号 - 力扣(LeetCode)

b1bbee2919574999a3acc186aef1318e.png

思路:我们可以创建一个栈,先把开口向右的括号全部入栈里面,当栈不为空的时候取栈顶元素;这步的操作其实就是实现当有{【( 这三个括号的时候能直接取到(,然后再和左开口的括号进行比较,如果说取出的栈顶元素是“(”,并且数组的下一个元素是“)”的话就是匹配上了,然后pos++;当不符合的时候直接返回false;如果不返回false一直到循环结束的时候就返回true,因为这说明全部括号都匹配上了;如下图和代码所示:f4d7dd70d5814d8eb8423f96547662e9.gif

#include<stdbool.h>
typedef char STDateType;
typedef struct Stack
{
    STDateType* arr;
    int top ;
    int capacity;
}ST;

void STInit(ST* st)
{
    st->arr=NULL;
    st->top = 0;
    st->capacity = 0;
}

void STPush(ST* st, STDateType x)
{
    if(st->capacity==st->top)
    {
        int Newcapacity = st->capacity==0?4:2*st->capacity;
        STDateType* temp = (STDateType*)realloc(st->arr, Newcapacity* sizeof(STDateType));
        if(temp==NULL)
        {
            perror("realloc fails!");
            exit(1);
        }
        st->arr = temp;
        st->capacity = Newcapacity;
    }
    st->arr[st->top++] = x;
}

bool STempty(ST* st)
{
    return st->top==0;
}

STDateType StackTop(ST* st)
{
    return st->arr[st->top-1];
}


void STPop(ST* st)
{
    assert(!STempty(st));
    --st->top;
}

void STDestory(ST* st)
{
    free(st->arr);
    st->arr = NULL;
    st->capacity = 0;
    st->top = 0;
}

bool isValid(char* s) 
{
    ST st;
    STInit(&st);
    char* ps = s;
    while(*ps!='\0')
    {
        if(*ps=='('||*ps=='{'||*ps=='[')
        {
            STPush(&st, *ps);
        }
        else
        {
            if(STempty(&st))
            {
                return false;
            }
            char ch = StackTop(&st);
            if((*ps==')'&&ch=='(')
            ||(*ps==']'&&ch=='[')
            ||(*ps=='}'&&ch=='{'))
            {
                STPop(&st);
            }
            else
            {
            STDestory(&st);
            return false;
            }
        }
        ps++;
    }
    bool ret = STempty(&st)==true;
    STDestory(&st);
    return ret;
}

这里还有几个需要注意的点是:

  1. 当栈为空的时候就代表没有开口向右的括号,那就没有意义再进行下去了,因为没有括号可以匹配;
  2. 在我们取栈顶元素比较完后要删除比较过的元素,因为取栈顶元素只是取值,并没有实现取并删;
  3. 到最后我们需要判断栈是否为空,栈不为空则说明多出了一个开口向右的括号例如"{ [ ( ) ]"这样是不符合的;

3.2 用队列实现栈

原题链接:225. 用队列实现栈 - 力扣(LeetCode)

2962997933e54fe2b04fb5d672f7fcf5.png

思路:首先我们先分析,队列是先进先出,栈是后进先出,那我们就先来使用1234进行模拟;如果把1234放到栈里面再取出来的话就是4321;8c7bb546caad4b6cba109aa25e5aee7b.png

那么如果说我们想用两个队列来实现的话就得换一种思路,因为队列是先进先出,那么我们就可以尝试先把数据放到一个队列里面,然后把size-1个数据放到另一个空队列里面,再把剩下的那个数据取出来,一直这样循环;如下图所示:fb6a1132c7964153b78083ce41209d1e.gif

typedef int QDataType;
typedef struct QueueNode 
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;

//队列
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* tail;
	int size;
}Queue;
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->tail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	//说明链表为空
	if (pq->phead == NULL)
	{
		pq->phead = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = pq->tail->next;
	}
	pq->size++;
}

//队列判空
bool QueueEmpty(Queue* pq)
{
	return pq->phead == NULL && pq->tail == NULL;
}

// 出队列,队头
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	//只有一个结点
	if (pq->tail == pq->phead)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->tail = NULL;
	}
	else
	{
		QueueNode* Del = pq->phead;
		pq->phead = pq->phead->next;
		free(Del);
	}
	--pq->size;
}


//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}
//队列有效元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->tail = NULL;
	pq->size = 0;
}


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

//初始化
MyStack* myStackCreate() 
{
    MyStack* temp = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&temp->q1);
    QueueInit(&temp->q2);
    return temp;
}

void myStackPush(MyStack* obj, int x) 
{
    //首先我们找哪个队列为空
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
        QueuePush(&obj->q2,x);
}

int myStackPop(MyStack* obj) 
{
    Queue* empQ = &obj->q1;
    Queue* noneQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        noneQ = &obj->q1;
        empQ = &obj->q2;
    }
    while(QueueSize(noneQ)>1) //大于1的原因是要留一个数据
    {
        int front = QueueFront(noneQ);
        QueuePush(empQ, front);
        QueuePop(noneQ);
    }
    int pop = QueueFront(noneQ);
    QueuePop(noneQ);
    return pop;
}

int myStackTop(MyStack* 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) 
{
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
    obj = NULL;

}

3.3 用栈实现队列

原题链接:232. 用栈实现队列 - 力扣(LeetCode)

e3654c89fadb41f695fbe27e6ee1f3d2.png

思路:首先我们分析,用两个栈实现队列的话,栈是先进后出,而队列是先进先出,我们使用1234来进行模拟;

队列是怎么进怎么出,1234进1234出;092b5c2eed7f462b81c50d77e4a8cb14.png

那么我们来看一下首先是堆,如果说我们直接把1234放进去,再取出来的话那就是4321,但是我们通过两个堆可以改变这个先让1234入一个名为pushST的堆,然后再让pushST堆的数据堆顶数据入一个名为popST的堆,这时候popST的堆的数据就为1234了;再取出来即可;那么用栈实现队列push数据到队列末尾的则只需要直接把数据放到堆顶即可;删除数据就如刚刚上面所说,取堆顶然后把最后一个数据留下来再把该数据删除就可以实现;取队头元素的实现也是如此;判空则是看两个堆是否都为空,都为空返回1即可;如下图和代码所示:652ea7dd28794dab9f01cff6063f0614.gif

typedef int STDatetype;

typedef struct Stack
{
	STDatetype* arr;
	int capacity;  //栈空间大小
	int top;       //栈顶
}ST;

void STInit(ST* st)
{
	st->arr = NULL;
	st->capacity = st->top = 0;
}
void STDestory(ST* st)
{
	if(st->arr)
		free(st->arr);
	st->arr = NULL;
	st->capacity = st->top = 0;
}

void StackPush(ST* ps, STDatetype x)
{
	if (ps->capacity == ps->top  )
	{
		int Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDatetype* temp = (STDatetype*)realloc(ps->arr, Newcapacity *sizeof(STDatetype) );
		if (temp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = Newcapacity;
	}
	ps->arr[ps->top++] = x;
}

bool StackEmpty(ST* ps)
{
	return ps->top == 0;
}

void StackPop(ST* ps)
{
	assert(!StackEmpty(ps));

	--ps->top;
}

//取栈顶元素
STDatetype StackTop(ST* ps)
{
	
	return ps->arr[ps->top-1];
}

//获取栈中有效元素个数
int STSize(ST* ps)
{
	return ps->top;
}



typedef struct 
{
    ST pushST;
    ST popST;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* pst = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&pst->pushST);
    STInit(&pst->popST);
    return pst;
}

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

int myQueuePop(MyQueue* obj) 
{
    if(StackEmpty(&obj->popST))
    {
        //为空就把pushST的数据放到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);
        }
    }
    return StackTop(&obj->popST);
}

bool myQueueEmpty(MyQueue* obj) 
{
    return StackEmpty(&obj->pushST) &&  StackEmpty(&obj->popST);
}

void myQueueFree(MyQueue* obj) 
{
    STDestory(&obj->pushST);
    STDestory(&obj->popST);
    free(obj);
    obj = NULL;
}

END!

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PCL 点云半径滤波

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 半径滤波实现 2.1.2 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#xf…

MFC有三个选项:MFC ActiveX控件、MFC应用程序、MFC DLL,如何选择?

深耕AI&#xff1a;互联网行业 算法研发工程师 ​ 目录 MFC ActiveX 控件 控件的类型 标准控件 自定义控件 ActiveX控件 MFC ActiveX控件 标准/自定义控件 MFC ActiveX控件分类 3种MFC如何选择&#xff1f; MFC ActiveX控件 MFC 应用程序 MFC DLL 总结 举例说明…

【JAVA开源】基于Vue和SpringBoot的周边产品销售网站

本文项目编号 T 061 &#xff0c;文末自助获取源码 \color{red}{T061&#xff0c;文末自助获取源码} T061&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

申请免费或试用VPS服务

申请免费或试用VPS服务 有时候我们特别希望能够找到一台像 Oracle Cloud 一样的永久免费 VPS&#xff08;需要满足一定的条件&#xff09;&#xff0c;可相对于其它厂商申请相对比较难&#xff0c;可能需要多次申请才能得到。其实&#xff0c;除了 Oracle Cloud 之外&#xff0…

阿里云对象存储OSS 速学

目录 1.创建一个Bucket 2.创建密钥AccessKey 3.在文档中心打开阿里云对象存储OSS 4.参考上传文件示例 以官网的文档为主&#xff0c;我的文章教学为辅 官网有详细的视频介绍&#xff1a; OSS快速入门_对象存储(OSS)-阿里云帮助中心 (aliyun.com)https://help.aliyun.com/…

Linux: network: 典型网络延迟图,CPU导致;

接上回说&#xff0c;https://mzhan017.blog.csdn.net/article/details/142689870&#xff1b; 其中在debug的过程中&#xff0c;看到下面这个IO图&#xff0c;这个图比较经典&#xff0c;是一个典型的网络延迟图&#xff0c;可用作为分析问题的一个参考。 如下图&#xff1a;黑…

C++ | Leetcode C++题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; class Solution { public:int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {unordered_map<int, int> countAB;for (int u: A) {for (int v: B) {count…

ZYNQ: GPIO 之 EMIO 按键控制 LED 实验

GPIO 之 EMIO 按键控制 LED 实验目的 使用启明星 ZYNQ 底板上的两个用户按键分别控制 PS 端两个 LED 的亮灭 其中一个按键 PL_KEY0 连接到了 PL 端&#xff0c;需要通过 EMIO 进行扩展&#xff0c;另外一个按键是底板上 PS 端的用户按键PS_KEY0&#xff0c;这两个按键分别控制…

堆的向上和向下调整

堆的物理结构和逻辑结构是什么&#xff1f; 堆如何插入数据和删除数据&#xff1f;为什么&#xff1f; 向上调整和向下调整的要求是啥&#xff1f; 文中不理解的可以先看堆的代码和基础知识-CSDN博客 也欢迎评论区一起讨论 1.堆的物理结构和逻辑结构 我们的堆是用数组实…

计算机毕业设计 视频点播系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

【AI知识点】维度灾难(curse of dimensionality)

维度灾难&#xff08;curse of dimensionality&#xff09; 是指在处理高维数据时&#xff0c;随着维度的增加&#xff0c;数据的性质和空间结构变得越来越复杂&#xff0c;导致许多常见的算法和技术在高维空间中效率低下或效果变差的问题。 这个概念最早是由Richard Bellman在…

RabbitMQ篇(基本介绍)

目录 一、MQ 1. 什么是MQ 2. 为什么要用MQ【业务场景】 2.1. 异步 2.2. 应用解耦 2.3. 流量削峰 3. MQ的分类 &#xff08;1&#xff09;ActiveMQ &#xff08;2&#xff09;Kafka &#xff08;3&#xff09;RocketMQ &#xff08;4&#xff09;RabbitMQ 4. MQ 的选…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02 1. APM: Large Language Model Agent-based Asset Pricing Models Authors: Junyan Cheng, Peter Chin https://arxiv.org/abs/2409.17266 APM: 基于大型语言模型的代理资产定价模型&#xff08;LLM Agent-b…

2、项目配置设计(上)

文章目录 前言一、配置文件功能需求二、web工程设计思路三、Config实现思路 前言 配置文件作用&#xff1a;把需要经常修改的参数&#xff0c;从代码中分离出来,单独管理&#xff0c;方便后期维护。 开发一个web应用&#xff0c;肯定需要一些基础性的配置信息&#xff0c;这些信…

骨架屏 (懒加载优化)

骨架屏 &#xff08;懒加载优化&#xff09; 即便通过 Webpack 的按需加载、CDN 静态资源缓存 和 代码分割 等技术来减少首屏的代码体积&#xff0c;首屏加载时的白屏时间&#xff08;也称为首屏等待时间&#xff09;仍然可能存在&#xff0c;尤其在网络条件较差或页面内容复杂…

【设计模式-解释模式】

定义 解释器模式是一种行为设计模式&#xff0c;用于定义一种语言的文法&#xff0c;并提供一个解释器来处理该语言的句子。它通过为每个语法规则定义一个类&#xff0c;使得可以将复杂的表达式逐步解析和求值。这种模式适用于需要解析和执行语法规则的场景。 UML图 组成角色…

基于Springboot vue应急物资供应管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…

【硬件模块】HC-SR04超声波模块

HC-SR04超声波模块实物图 工作参数 探测距离&#xff1a;2~600cm 探测精度&#xff1a;0.1cm1% 感应角度&#xff1a;<15 输出方式&#xff1a;GPIO 工作电压&#xff1a;DC 3~5.5V 工作电流&#xff1a;5.3mA 工作温度&#xff1a;-40~85℃ 引脚接线 HC-SR04MCU备注VC…

Golang | Leetcode Golang题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; func fourSumCount(a, b, c, d []int) (ans int) {countAB : map[int]int{}for _, v : range a {for _, w : range b {countAB[vw]}}for _, v : range c {for _, w : range d {ans countAB[-v-w]}}return }

04-SpringBootWeb案例(下)

3. 员工管理 完成了部门管理的功能开发之后&#xff0c;我们进入到下一环节员工管理功能的开发。 基于以上原型&#xff0c;我们可以把员工管理功能分为&#xff1a; 分页查询&#xff08;今天完成&#xff09;带条件的分页查询&#xff08;今天完成&#xff09;删除员工&am…