【栈和队列】的特性以及基本接口的实现

news2024/11/27 8:33:58

目录

一、栈

1.1 栈的概念

1.2 栈的接口实现

二、队列

2.1 队列的概念

2.2 队列的接口实现

2.3 栈和队列的区别

三、栈和队列LeetCode练习

3.1 力扣_232.用栈实现队列

3.2 力扣_225.用队列实现栈

3.3 力扣_622.设计循环队列

3.4 力扣_20.有效的括号


一、栈

第一次学习数据结构的小伙伴们不要把栈想的很难,实际上挺简单的。只要搞清楚一点:“后进先出,先进后出” 就OK了!

1.1 栈的概念

对于逻辑关系为“一对一”的数据,除了用顺序表和链表存储外,还可以用栈结构存储。

栈是一种“特殊”的线性存储结构,它的特殊之处体现在以下两个地方:

1、元素进栈和出栈的操作只能从一端完成,另一端是封闭的,如下图所示:

 通常,我们将元素进栈的过程简称为“入栈”、“进栈”或者“压栈”;将元素出栈的过程简称为“出栈”或者“弹栈”

2、栈中无论存数据还是取数据,都必须遵循“先进后出”的原则,即最先入栈的元素最先出栈。以上图的栈为例,很容易可以看出是元素 1 最先入栈,然后依次是元素 2、3、4 入栈。在此基础上,如果想取出元素 1,根据“先进后出”的原则,必须先依次将元素 4、3、2 出栈,最后才能轮到元素 1 出栈。

我们习惯将栈的开口端称为栈顶,封口端称为栈底。

由此我们可以对栈存储结构下一个定义:栈是一种“只能从一端存取元素,且存取过程必须遵循‘先进后出’原则”的线性存储结构。

1.2 栈的接口实现

//Stack.h文件


#pragma once


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

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


//初始化栈
void STInit(ST* pst);

//入栈
void STPush(ST* pst, DataType x);

//出栈
void STPop(ST* pst);

//栈的销毁
void STDestory(ST* pst);

//得到栈顶元素
DataType STGetTop(ST* pst);

//判断栈是否为空
bool STEmpty(ST* pst);

//栈的大小——元素个数
int STSize(ST* pst);
//Stack.c文件


#include "Stack.h"

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

void STPush(ST* pst, DataType x)
{
	assert(pst);

	//扩容
	if (pst->top == pst->capacity)
	{
		int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		DataType* tmp = (DataType*)realloc(pst->data, sizeof(DataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail!\n");
			return;
		}
		pst->data = tmp;
		pst->capacity = newCapacity;
	}

	//入栈
	pst->data[pst->top] = x;
	pst->top++;
}

void STPop(ST* pst)
{
	assert(pst);

	assert(!STEmpty(pst));

	pst->top--;
}

void STDestory(ST* pst)
{
	assert(pst);
	free(pst->data);
	pst->data = NULL;
	pst->top = 0;
	pst->capacity = 0;
}



DataType STGetTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));

	return pst->data[pst->top - 1];
}

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}



int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

二、队列

2.1 队列的概念

队列用来存储逻辑关系为“一对一”的数据,是一种“特殊”的线性存储结构。和顺序表、链表相比,队列的特殊性体现在以下两个方面:

1、元素只能从队列的一端进入,从另一端出去,如下图所示: 

通常,我们将元素进入队列的一端称为“队尾”,进入队列的过程称为“入队”;将元素从队列中出去的一端称为“队头”,出队列的过程称为“出队”

2、队列中各个元素的进出必须遵循“先进先出”的原则,即最先入队的元素必须最先出队。

以上图所示的队列为例,从各个元素在队列中的存储状态不难判定,元素 1 最先入队,然后是元素 2 入队,最后是元素 3 入队。如果此时想将元素 3 出队,根据“先进先出”原则,必须先将元素 1 和 2  依次出队,最后才能轮到元素 3 出队。

2.2 队列的接口实现

//Queue.h文件


#pragma once


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

typedef int DataType;
typedef struct QNode
{
	DataType data;
	struct QNode* next;
}QNode;

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

//初始化队列
void QueueInit(Queue* pq);

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

//入队
void QueuePush(Queue* pq, DataType x);


//出队
void QueuePop(Queue* pq);

//队头元素
DataType QueueFront(Queue* pq);

//队尾元素
DataType QueueBack(Queue* pq);

//队列的大小
int QueueSize(Queue* pq);

//判断队列是否为空
bool QueueEmpty(Queue* pq);
//Queue.c文件


#include "Queue.h"

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

void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = NULL;
	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!\n");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;


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

void QueuePop(Queue* pq)
{
	assert(pq);

	//没有节点
	assert(!QueueEmpty(pq));
	//只有一个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->ptail = NULL;
	}

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

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

DataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->ptail->data;
}

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

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
}

2.3 栈和队列的区别

栈和队列不要混淆,栈是一端开口、另一端封口,元素入栈和出栈遵循“先进后出”原则;队列是两端都开口,但元素只能从一端进,从另一端出,且进出队列遵循“先进先出”的原则。

三、栈和队列LeetCode练习

3.1 力扣_232.用栈实现队列

typedef struct {
    ST PushST;
    ST PopST;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->PushST);
    STInit(&obj->PopST);

    return obj;
}

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

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

int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&obj->PopST))
    {
        while(!STEmpty(&obj->PushST))
        {
            STPush(&obj->PopST, STGetTop(&obj->PushST));
            STPop(&obj->PushST);
        }
    }
    return STGetTop(&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);
}

3.2 力扣_225.用队列实现栈

 

typedef struct {
    Queue q1;
    Queue q2;

} MyStack;


MyStack* myStackCreate() {
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    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) {
    Queue* EmptyQ = &obj->q1;
    Queue* NoEmptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        EmptyQ = &obj->q2;
        NoEmptyQ = &obj->q1;
    }

    while(QueueSize(NoEmptyQ) > 1)
    {
        QueuePush(EmptyQ, QueueFront(NoEmptyQ));
        QueuePop(NoEmptyQ);
    }
    int top = QueueFront(NoEmptyQ);
    QueuePop(NoEmptyQ);
    return top;
}

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) {
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);

    free(obj);
}

3.3 力扣_622.设计循环队列

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


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

    return obj;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

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


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 obj->a[obj->front];
    else
        return -1;
}

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


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

3.4 力扣_20.有效的括号

bool isValid(char * s)
{
    ST st;
    STInit(&st); 
    while(*s)
    {
        if(*s == '(' || *s == '[' || *s == '{')
        {
            STPush(&st, *s);
        }
        else
        {
            if(STEmpty(&st))
            {
                STDestory(&st);
                return false;
            }
            char top = STGetTop(&st);
            STPop(&st);
            if(*s == ')' && top != '('
            || *s == ']' && top != '['
            || *s == '}' && top != '{')
            {
                STDestory(&st);
                return false;
            }
        }
        s++;
    }
    bool ret = STEmpty(&st);
    STDestory(&st);
    return ret;
}

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

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

相关文章

电容在电路中的作用

电容、也称为电容器&#xff0c;字面意思理解就是一种“装电的容器”&#xff0c;是一种容纳电荷的器件。它拥有两个电极板&#xff0c;由两个电极板及其中间所夹的介质封装而成。 常用电容极性判断&#xff1a;   铝电解电容&#xff1a;长脚为正极&#xff0c;短脚为负极&…

【MySQL学习】MySQL索引特性

文章目录 一、初识MySQL索引1.1 MySQL索引的概念1.2 MySQL索引的作用 二、MySQL的数据存储2.1 MySQL存储与磁盘之间的关系2.2 MySQL与磁盘交互的基本单位2.3 认识数据页Page 三、索引的理解3.1 测试案例3.2 探究单个和多个Page存储数据时的情况3.3 页目录3.4 为什么InooDB存储引…

《面试1v1》CAS

我是 javapub&#xff0c;一名 Markdown 程序员从&#x1f468;‍&#x1f4bb;&#xff0c;八股文种子选手。 面试官&#xff1a; 上个面试官对你的基础有了一定了解&#xff0c;听说你小子很不错&#xff01;下面我们聊点有深度的。 面试官&#xff1a; 简单介绍下 CAS 你了…

10款Photoshop免费在线工具推荐

AdobePhotoshop下载繁琐&#xff0c;付费昂贵&#xff0c;让很多设计师望而却步&#xff01; 经过几个小时的筛选和测试&#xff0c;筛选出10款Photoshop免费在线工具&#xff0c;与Photoshop一样强大。让我们看看&#xff01; 1.即时设计 智能抠图 当我们想要去重图片背景&…

【鲁棒优化、机会约束】具有分布鲁棒联合机会约束的能源和储备调度研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

JAVA中的深情哥-Exception(异常)-上

文章目录 目录 文章目录 前言 一&#xff0c;Exception的起源 二&#xff0c;异常类 三&#xff0c;自定义异常 总结 前言 大家好,我是最爱吃兽奶,今天给大家介绍一下java中的深情哥 - Exception 秋风依依秋水寒&#xff0c;一点离愁两黯然&#xff1b;今生默默唯轻舞&a…

抖音林客系统开发

抖音林客系统是一款基于AI技术的推荐算法系统&#xff0c;主要应用于抖音平台中用户的内容推荐和个性化服务。开发抖音林客系统需要掌握以下关键技术&#xff1a; 数据采集与处理&#xff1a;需要对海量的用户数据进行采集和处理&#xff0c;包括用户的观看历史、互动行为、…

K-Village NFT 作品集

K-Village 是韩国领先的娱乐公司和 Cube 娱乐公司所拥有的空间&#xff0c;引领了元宇宙行业的发展。在这个虚拟的「韩国村」中&#xff0c;可以参观代表韩国文化的韩国公司和品牌。 此外&#xff0c;这个系列的购买者还将获得特别奖励&#xff01;如果你刚好拥有 20 个 K-Vill…

不懂Spring IOC?你可能已经OUT了!快来了解它的奥秘!

大家好&#xff0c;我是小米&#xff0c;一个热衷于技术分享的小伙伴。今天&#xff0c;我想和大家聊一聊Spring IoC&#xff08;Inversion of Control&#xff09;的理解、原理与实现。对于使用Spring框架的开发者来说&#xff0c;IoC容器是一个非常重要的概念&#xff0c;它帮…

C++ ---- 日期类实现+阅读文档(文档可直接下载)

日期类文档下载(日期类详细介绍) word文档 MyDate/MyDate/日期类阅读文档.docx 张喜阳/进阶代码仓库 - Gitee.comhttps://gitee.com/niuniuzxy/advanced-code-warehouse/blob/a25baeee2bd0f0c64f96315bb0d0023308329d92/MyDate/MyDate/%E6%97%A5%E6%9C%9F%E7%B1%BB%E9%98%85…

十六、Config分布式配置中心

目录 分布式配置中心概述 1、为什么需要分布式配置中心&#xff1f; 2、配置中心的作用&#xff1a; Spring Cloud Config简介 新建项目springcloud-config-server 1、引入配置中心config-server的依赖 2、在github/gitee上新建一个远程仓库作为config的远程配置中心 3、…

3年测试技术面一题都看不懂,字节面试真的变态.....

最近我的一个读者朋友去了字节面试&#xff0c;来给我发信息吐槽&#xff0c;说字节的面试太困难了&#xff0c;像他这种三年经验的测试员&#xff0c;在技术面&#xff0c;居然一题都答不上来&#xff0c;这要多高的水平才能有资格去面试字节的测试岗位。 确实&#xff0c;字…

Vue2+CSS实现一个瀑布流布局案例

在练习代码的时候&#xff0c;看到了携程的首页下方的布局还挺好看 就是一个瀑布流的布局效果&#xff0c;在携程上是一共两列布局&#xff0c;然后每个格子的高度都会根据图片的高度做排布 一开始是想使用flex进行布局&#xff0c;先让每个格子各占百分之49&#xff0c;然后贴…

微信小程序实现电子书搜索与下载

1、背景 自己已经做了一版电子书下载网站&#xff08;走蛟电子书&#xff09;&#xff0c;但用户使用手机更方便些&#xff0c;为改善用户体验&#xff0c;准备做一款微信小程序实现电子书搜索与下载的功能。 2、技术栈 由于功能较为单一&#xff0c;因此前端使用原生的微信…

CSS基础语法

CSS基础语法知识 文章目录 CSS基础语法1. CSS的引入方式1.1 内部样式1.2 外部样式1.3 内联样式 2. CSS标签选择器2.1 标签选择器2.2 类选择器2.3 id选择器2.4 复合选择器 3. CSS常见属性3.1 字体相关3.2 文本相关3.3 颜色的写法3.4 背景相关3.5 边框相关3.6 元素的显示模式3.7 …

【链表应用】| 一元多项式的操作

目录 一. &#x1f981; 要求:二. 代码实现&#xff08;Java & c&#xff09;1. Java实现2.C语言实现 三. &#x1f981; 总结 一. &#x1f981; 要求: 设有两个一元多项式: p(x)p0p1xp2x2pnxn q(x)q0q1xq2x2qmxm 多项式项的系数为实数&#xff0c;指数为整数&#xff0c…

11个免费的数据可视化工具推荐

数据可视化之所以流行&#xff0c;不仅是因为它简化了我们查看复杂数据的方式&#xff0c;更是因为数据可视化可以加快我们获取数据信息的速度。 本文专门为您列出了11个免费的数据可视化工具&#xff0c;帮助您快速掌握数据可视化技能。 1.即时设计 即时设计是可云端编辑的…

物通博联工业物联网解决方案,助力工厂实现设备远程运维

各类设备制造工厂随着经营规模与业务的扩张&#xff0c;设备可以销往全国各地甚至是全球&#xff0c;是工厂实力的体现。当设备越来越多、分布越来越广&#xff0c;设备管理的工作量和成本直线上升&#xff0c;可能面对维护不及时的情况&#xff0c;影响到客户经济效益和对工厂…

spark源码 spark on yarn环境的创建

1.入口类 sparkSubmit 的main方法 提交application submitnew SparkSubmit submit.doSubmit(args) -> super.doSubmit(args): parseArguments(args) &#xff1a;参数解析 方法 中 new sparkSubmitArguments(args) 点进去该类(主要解析参数)&#xff0c;然后找到parse&am…

C/C++ 内存管理 new delete operator new与operator delete函数 内存泄漏

C/C 内存分布 在C/C 当中有 &#xff1a; 局部数据静态数据和全局数据常量数据动态申请数据 上述不同的数据存储的位置也不同&#xff0c;&#xff1a; 1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等&#xff0c;栈是向下增长的。2. 内存映射段是高效的I/O映射方式&…