【数据结构】栈和队列详解

⭐️ 往期相关文章

✨链接1:数据结构和算法的概念以及时间复杂度空间复杂度详解
✨链接2:【数据结构】手撕顺序表
✨链接3:【数据结构】手撕单链表
✨链接4:【数据结构】双向带头循环链表


⭐️ 栈和队列

🌠 栈

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

图:
在这里插入图片描述


🌠 栈的实现

栈的实现一般可以使用数组或链表实现,相对而言数组的结构实现更优一些,数组实现可以让下标为 0 的这一端当作栈底,另一端当作栈顶,并使用一个 top 下标记录着栈定的位置,那么当 push 元素的时候只需要 O ( 1 ) O(1) O(1) 的复杂度实现插入,删除也是一样。如果采用链表实现,每次 push 元素时需要尾插,单链表的话需要每次找尾结点,这样时间复杂度就是 O ( N ) O(N) O(N) 了,或者也可以定义一个 tail 尾结点,每次则不需要找尾,但是出栈的时候又是一个问题,因为删除 tail 尾结点还需要把 tail 往前移动一下,但是此时找不到 tail 的前一个结点,还是需要遍历找 tail 结点的前一个结点。所以如果是用链表实现栈的话,最好是链表的尾部当作栈底,链表头结点当作栈顶,这样的话链表的头插头删时间复杂度都是 O ( 1 ) O(1) O(1)我们本章主要采用数组来实现栈

栈的接口

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int StackType;typedef struct Stack {StackType* data;	int top;			// 栈顶int capacity;		// 容量
}Stack;// 栈的初始化
void StackInit(Stack * ps);
// 栈的销毁
void StackDestroy(Stack * ps);
// 入栈
void StackPush(Stack* ps , StackType node);
// 出栈
void StackPop(Stack* ps);
// 栈是否为空
bool StackEmpty(Stack* ps);
// 栈的大小
int StackSize(Stack* ps);
// 取栈顶元素
StackType StackTop(Stack * ps);

StackInit 实现

void StackInit(Stack* ps) {assert(ps);ps->data = NULL;ps->top = 0;ps->capacity = 0;
}

StackDestroy 实现

void StackDestroy(Stack* ps) {assert(ps);free(ps->data);ps->data = NULL;ps->top = 0;ps->capacity = 0;
}

StackPush 实现

void StackPush(Stack* ps , StackType node) {assert(ps);// 检查容量if (ps->top == ps->capacity) {int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;StackType* newData = (StackType*)realloc(ps->data , sizeof(StackType) * newCapacity);assert(newData);ps->data = newData;ps->capacity = newCapacity;}ps->data[ps->top] = node;ps->top++;
}

StackPop 实现

void StackPop(Stack* ps) {assert(ps);// 判断栈是否为空assert(!StackEmpty(ps));ps->top--;
}

StackTop 实现

StackType StackTop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));return ps->data[ps->top - 1];
}

StackEmpty 实现

bool StackEmpty(Stack* ps) {assert(ps);// 空为真,非空返回0return ps->top == 0;
}

StackSize 实现

int StackSize(Stack* ps) {assert(ps);return ps->top;
}

🌠 队列

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

图:
在这里插入图片描述

🌠 队列的实现

队列和栈一样都可以使用数组和链表的结构来实现,但是如果选择数组实现队列的话,下标为 0 的一端是队头,另一端是队尾,那么插入数据的时间复杂度是 O ( 1 ) O(1) O(1)但是当从队头删除数据的时候,数组需要从后往前挪动数据,效率较低。而使用链表实现队列,单链表的头删是 O ( 1 ) O(1) O(1) 的操作,但是如果要从队尾入数据单链表需要找尾,所以我们这里可以定义两个指针 headtail 这样单链表尾插时间复杂度 O ( 1 ) O(1) O(1) 就不需要每次入队列找尾结点了。所以使用队列使用链表来实现更优。

队列的接口

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int QueueDataType;// 单链表实现队列
typedef struct QueueNode {QueueDataType data;struct QueueNode* next;
}QueueNode;typedef struct Queue {QueueNode* head;	// 指向队头QueueNode* tail;	// 指向队尾
}Queue;// 队列的初始化
void QueueInit(Queue* q);
// 队列的销毁
void QueueDestroy(Queue* q);
// 队尾入数据
void QueuePush(Queue* q , QueueDataType x);
// 队头出数据
void QueuePop(Queue* q);
// 判断队列是否为空
bool QueueIsEmpty(Queue* q);
// 获取队头数据
QueueDataType QueueFront(Queue* q);
// 获取队尾数据
QueueDataType QueueBack(Queue* q);
// 获取队列有效元素的个数
int QueueSize(Queue* q);

QueueInit 实现

void QueueInit(Queue* q) {assert(q);q->head = NULL;q->tail = NULL;
}

QueueDestroy 实现

void QueueDestroy(Queue* q) {assert(q);QueueNode* cur = q->head;while (cur) {QueueNode* next = cur->next;free(cur);cur = next;}q->head = q->tail = NULL;
}

QueuePush 实现

void QueuePush(Queue* q , QueueDataType x) {assert(q);// 创建新结点QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));assert(newNode);newNode->data = x;newNode->next = NULL;// 没有结点的情况if (q->tail == NULL) {q->head = q->tail = newNode;}else {// 多个结点的情况q->tail->next = newNode;q->tail = q->tail->next;}
} 

QueuePop 实现

void QueuePop(Queue* q) {assert(q);// 空队列assert(!QueueIsEmpty(q));// 一个结点的情况if (q->head->next == NULL) {	// q->head == q->tailfree(q->head);q->head = q->tail = NULL;}else {// 多个结点的情况QueueNode* next = q->head->next;free(q->head);q->head = next;}
}

QueueIsEmpty 实现

bool QueueIsEmpty(Queue* q) {assert(q);return q->head == NULL;
}

QueueFront 实现

QueueDataType QueueFront(Queue* q) {assert(q);// 空队列assert(!QueueIsEmpty(q));return q->head->data;	// 返回队头数据
}

QueueBack 实现

QueueDataType QueueBack(Queue* q) {assert(q);// 空队列assert(!QueueIsEmpty(q));return q->tail->data;	// 返回队尾数据
}

QueueSize 实现

int QueueSize(Queue* q) {assert(q);int size = 0;QueueNode* cur = q->head;while (cur != NULL) {size++;cur = cur->next;}return size;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机视觉 | 图像分割】arxiv 计算机视觉关于图像分割的学术速递(7 月 6 日论文合集)

文章目录 一、分割|语义相关(15篇)1.1 Prompting Diffusion Representations for Cross-Domain Semantic Segmentation1.2 ZJU ReLER Submission for EPIC-KITCHEN Challenge 2023: Semi-Supervised Video Object Segmentation1.3 Multi-Modal Prototypes for Open-Set Semanti…

Kafka学习笔记(基础篇)

目录 Kafka简介 消息队列 Kafka的应用场景 消息队列的两种模型 Kafka集群搭建 Kafka的生产者/消费者/工具 Kafka的基准测试工具 Kafka Java API开发 生产者程序开发 消费者程序开发 生产者使用异步方式生产消息 Kafka中的重要概念 消费者组 幂等性 事务编程 Ka…

故障:启动修复无法修复你的电脑

有台笔记本很久没用了无法开机了&#xff0c;还是用的win7的系统&#xff0c;开机后提示我使用启动修复&#xff0c;但是失败了&#xff0c;提示我启动修复无法修复你的电脑 启动修复无法修复你电脑怎么办_自动修复电脑未正确启动的解决方法&#xff0d;win7之家 1、上网查了下…

图形学 | 期末复习(下)| games101笔记 | 补档

博客基于GAMES101-现代计算机图形学入门-闫令琪&#xff0c;但不是其完整笔记&#xff0c;基于复习要求有一定的删减。考试以图形学入门基本概念和核心研究内容为主&#xff0c;少量公式。即以论述概念为主&#xff0c;涉及少量算法。p13:3:12是对应的games101视频节点。 文章目…

解决printJS打印问题汇总

目录 一、打印预览表格列不全&#xff08;Element的el-table组件&#xff09; 1、打印设置“打印缩放” 2、修改el——table的底层代码&#xff08;如果页面上有多个表格慎用&#xff09; 一、打印预览表格列不全&#xff08;Element的el-table组件&#xff09; 问题描述&a…

zookeeper第一课-Zookeeper特性与节点数据类型详解

1、Zookeeper特性与节点数据类型详解 ZooKeeper 是一个开源的分布式协调框架&#xff0c;是Apache Hadoop 的一个子项目&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。 Zookeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来&#xff0c;构成一…

Ubuntu下Go语言TCP广播服务器实现

最近在学习Go语言网络编程&#xff0c;突然想到很久以前的用C语言写过的TCP广播聊天程序&#xff0c;然后就用Go尝试写了一遍&#xff0c;在此做个记录。 目录 1.广播结构 2.实现效果 3.源码 4.Go语言学习参考网站 1.广播结构 2.实现效果 服务器&#xff1a; 客户端1&…

计算机毕业论文内容参考|基于Python的入侵检测系统的设计与实现

文章目录 导文摘要前言绪论课题背景国内外现状与趋势课题内容相关技术与方法介绍系统分析系统设计系统实现系统测试总结与展望导文 计算机毕业论文内容参考|基于Python的入侵检测系统的设计与实现 摘要 本文介绍了基于Python的入侵检测系统的设计与实现。首先,简要概述了入侵…

语言模型BERT理解

一、BERT概述 BERT是由Google在2018年提出的一种预训练语言模型。BERT的创新之处在于采用了双向Transformer编码器来生成上下文相关的词向量表示。 传统的单向语言模型只考虑了左侧或右侧的上下文信息&#xff0c;而BERT则同时考虑了左侧和右侧的上下文信息&#xff0c;使得生…

uni-app获取系统信息(手机牌子、手机型号、屏幕宽度、屏幕高度)

uni.getSystemInfo({success(res) {console.log(res.brand) //手机牌子console.log(res.model) //手机型号console.log(res.screenWidth) //屏幕宽度console.log(res.screenHeight) //屏幕高度}) .exec()}}); 如下 官网链接&#xff1a;系统信息的概念 | uni-app官网

【ES6】中构造函数的语法糖 —— Class(类)

在现代前端开发中&#xff0c;JavaScript的面向对象编程成为了主流。ES6引入了class关键字&#xff0c;使得开发者可以更方便地使用面向对象的方式编写代码&#xff0c;更接近传统语言的写法。ES6的class可以看作是一个语法糖&#xff0c;它的绝大部分功能ES5都可以做到&#x…

Leetcode每日一题:167. 两数之和 II - 输入有序数组(2023.7.8 C++)

目录 167. 两数之和 II - 输入有序数组 题目描述&#xff1a; 实现代码与解析&#xff1a; 暴力&#xff08;超时&#xff09; 双指针 原理思路&#xff1a; 二分 原理思路&#xff1a; 167. 两数之和 II - 输入有序数组 题目描述&#xff1a; 给你一个下标从 1 开始的…