数据结构--》深入了解栈和队列,让算法更加高效

这篇具有很好参考价值的文章主要介绍了数据结构--》深入了解栈和队列,让算法更加高效。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        本文将带你深入了解数据结构栈和队列,这两种基础的线性数据结构在算法中的重要性不言而喻。我们将会详细介绍栈和队列的概念、分类、实现以及应用场景,在理解栈和队列的基础上,还将探讨如何通过栈和队列来高效地解决算法问题。

        无论你是初学者还是进阶者,本文将为你提供简单易懂、实用可行的知识点,帮助你更好地掌握栈和队列,进而提升算法解题的能力,开启数据结构与算法的奇妙之旅。

目录

栈的基本概念

栈的顺序存储与链式存储实现

栈在表达式中的应用

队列的基本概念

队列的顺序和链式实现


栈的基本概念

        栈(Stack)是一种线性数据结构,它的特点是只能在末端(栈顶)进行插入和删除操作,并且访问元素时也是从栈顶开始。栈的行为类似于弹簧被压缩的过程,当一个元素被插入栈中时,它就被压入栈底;而当一个元素被删除时,它就从栈顶弹出。

        由于栈的后进先出(Last-In-First-Out,LIFO)的特性,因此它常用于需要“回溯”的算法实现,例如递归、深度优先搜索等。在计算机科学中,栈也被广泛应用于表达式求值、函数调用、内存管理等方面。

栈可以通过数组或链表来实现。通过数组实现的栈称为顺序栈,而通过链表实现的栈称为链式栈。无论通过何种方式实现,栈的基本操作包括入栈(push)、出栈(pop)、查看栈顶元素(top)以及判断栈是否为空(empty)。

栈的基本操作如下

InitStack(&S):初始化栈。构造一个空栈S,分配内存空间。

DestroyStack(&L):销毁栈。销毁并释放栈S所占用的内存空间。

Push(&S,x):进栈,若栈S未满,则将x加入使之成为栈顶。

Pop(&S,&x):出栈,若栈S非空,则弹出栈顶元素,并用x返回。

GetTop(S,&x):读栈顶元素。若栈S非空,则用x返回栈顶元素

其他常用操作

StackEmpty(S):判断一个栈S是否为空。若S为空,则返回true,否则返回false。

栈的常考题型为:

数据结构--》深入了解栈和队列,让算法更加高效

数据结构--》深入了解栈和队列,让算法更加高效

数据结构--》深入了解栈和队列,让算法更加高效

回顾重点,其主要内容整理成如下内容: 

数据结构--》深入了解栈和队列,让算法更加高效

栈的顺序存储与链式存储实现

栈可以通过两种方式来实现:顺序存储链式存储

        顺序存储的栈,即顺序栈,通常使用数组来实现。在顺序栈中,栈底在数组的低地址处,栈顶在数组的高地址处。栈顶指针(top)是一个整型变量,它指向当前栈顶元素所在的位置。当栈为空时,top的值为-1。入栈操作就是将元素插入到top位置的后面,然后将top指针向上移动一个位置;出栈操作就是将top指针向下移动一个位置,然后将该位置的元素删除。

const int MAX_SIZE = 100; // 定义栈的最大容量
int stack[MAX_SIZE]; // 定义栈数组
int top = -1; // 初始化栈顶指针为-1,表示栈为空

// 入栈操作
void push(int x) {
    if (top == MAX_SIZE - 1) { // 栈满,无法继续插入元素
        cout << "Error: Stack overflow!" << endl;
        return;
    }
    top++; // 栈顶指针上移
    stack[top] = x; // 将元素x插入栈顶位置
}

// 出栈操作
void pop() {
    if (top == -1) { // 栈空,无法进行出栈操作
        cout << "Error: Stack underflow!" << endl;
        return;
    }
    top--; // 栈顶指针下移
}

// 获取栈顶元素
int getTop() {
    if (top == -1) { // 栈为空,栈顶指针无效
        cout << "Error: Stack is empty!" << endl;
        return -1;
    }
    return stack[top]; // 返回栈顶元素
}

// 判断栈是否为空
bool isEmpty() {
    return top == -1; // 栈顶指针为-1时,栈为空
}

栈的顺序存储还有一种共享栈的方式。共享栈是一种特殊的顺序栈,它可以同时存储两个栈。具体来说,共享栈有两个栈顶指针,分别指向两个栈的栈顶元素。它们从两端向中间生长,当它们相遇时就表示栈满了。共享栈常用于两个栈需要共用一段连续的存储空间的情况,例如某些操作系统的内核栈和用户栈都共用一个物理内存区域。下面是使用 C++ 实现共享栈的完整代码示例:

#include <iostream>
using namespace std;

const int MAX_SIZE = 100; // 定义栈的最大容量

int stack[MAX_SIZE]; // 定义存储栈元素的数组
int top1 = -1; // 定义第一个栈的栈顶指针,初始值为-1
int top2 = MAX_SIZE; // 定义第二个栈的栈顶指针,初始值为MAX_SIZE

// 向第一个栈中插入元素
void pushStack1(int x) {
    if (top1 + 1 == top2) { // 共享栈已满
        cout << "Error: Stack overflow!" << endl;
        return;
    }
    top1++; // 第一个栈的栈顶指针上移
    stack[top1] = x; // 在第一个栈中插入元素
}

// 向第二个栈中插入元素
void pushStack2(int x) {
    if (top1 + 1 == top2) { // 共享栈已满
        cout << "Error: Stack overflow!" << endl;
        return;
    }
    top2--; // 第二个栈的栈顶指针下移
    stack[top2] = x; // 在第二个栈中插入元素
}

// 从第一个栈中删除元素
void popStack1() {
    if (top1 == -1) { // 第一个栈为空
        cout << "Error: Stack underflow!" << endl;
        return;
    }
    top1--; // 第一个栈的栈顶指针下移
}

// 从第二个栈中删除元素
void popStack2() {
    if (top2 == MAX_SIZE) { // 第二个栈为空
        cout << "Error: Stack underflow!" << endl;
        return;
    }
    top2++; // 第二个栈的栈顶指针上移
}

// 获取第一个栈的栈顶元素
int getTop1() {
    if (top1 == -1) { // 第一个栈为空,栈顶指针无效
        cout << "Error: Stack is empty!" << endl;
        return -1;
    }
    return stack[top1]; // 返回第一个栈的栈顶元素
}

// 获取第二个栈的栈顶元素
int getTop2() {
    if (top2 == MAX_SIZE) { // 第二个栈为空,栈顶指针无效
        cout << "Error: Stack is empty!" << endl;
        return -1;
    }
    return stack[top2]; // 返回第二个栈的栈顶元素
}

// 判断第一个栈是否为空
bool isEmpty1() {
    return top1 == -1; // 第一个栈的栈顶指针为-1时,栈为空
}

// 判断第二个栈是否为空
bool isEmpty2() {
    return top2 == MAX_SIZE; // 第二个栈的栈顶指针为MAX_SIZE时,栈为空
}

int main() {
    pushStack1(1);
    pushStack1(2);
    pushStack2(3);
    pushStack2(4);

    cout << "Top of Stack 1: " << getTop1() << endl;
    cout << "Top of Stack 2: " << getTop2() << endl;

    popStack1();
    popStack2();

    cout << "Top of Stack 1: " << getTop1() << endl;
    cout << "Top of Stack 2: " << getTop2() << endl;

    return 0;
}

在主函数中,我们演示了如何使用 pushStack1()、pushStack2()、popStack1()、popStack2()、getTop1() 和 getTop2() 等操作来对共享栈进行插入、删除和获取元素等操作,并输出了两个栈的栈顶元素。

数据结构--》深入了解栈和队列,让算法更加高效

回顾重点,其主要内容整理成如下内容:  

数据结构--》深入了解栈和队列,让算法更加高效

栈的链式存储实现方式是使用链表来存储栈中的元素。栈顶指针 Top 指向链表的头节点,每插入一个元素就在链表的头部插入一个节点,每删除一个元素就删除链表头部的节点,这样就实现了栈的先进后出的特性。 以下是使用 C++ 语言实现的栈链式存储的完整代码:

#include <iostream>
using namespace std;

// 定义链表的节点结构体
struct Node {
    int data; // 节点中存储的数据
    Node* next; // 指向下一个节点的指针
};

// 定义链表的头指针和栈顶指针
Node* head = NULL;
Node* top = NULL;

// 向栈中插入元素
void push(int x) {
    Node* newNode = new Node; // 创建新节点
    newNode->data = x; // 将元素值赋给新节点的 data 域
    newNode->next = top; // 新节点的 next 指向当前栈顶节点
    top = newNode; // 更新栈顶指针
}

// 从栈中删除元素
void pop() {
    if (top == NULL) { // 栈为空,无法删除
        cout << "Error: Stack is empty!" << endl;
        return;
    }
    Node* temp = top; // 暂存当前栈顶节点的地址
    top = top->next; // 更新栈顶指针
    delete temp; // 释放暂存节点内存空间
}

// 获取栈顶元素
int getTop() {
    if (top == NULL) { // 栈为空,栈顶指针无效
        cout << "Error: Stack is empty!" << endl;
        return -1;
    }
    return top->data; // 返回栈顶节点的 data 域
}

// 判断栈是否为空
bool isEmpty() {
    return top == NULL; // 栈顶指针为空时,栈为空
}

int main() {
    push(1);
    push(2);
    push(3);

    cout << "Top of Stack: " << getTop() << endl;

    pop();
    pop();

    cout << "Top of Stack: " << getTop() << endl;

    return 0;
}

在主函数中,我们演示了如何使用 push()、pop() 和 getTop() 等操作来对栈进行插入、删除和获取元素等操作,并输出了栈顶元素。 

数据结构--》深入了解栈和队列,让算法更加高效

栈在表达式中的应用

栈在表达式中的应用非常广泛,可以用来进行中缀表达式的转换计算后缀表达式等操作。中缀表达式是指形如 a+b 或 (a+b)*c-d/(e+f) 这样的表达式,其中运算符位于两个操作数的中间。但是在计算机中,通常采用后缀表达式(也叫逆波兰表达式)来表示算术表达式,即把运算符放在操作数后面,例如 a b + c * d /。

数据结构--》深入了解栈和队列,让算法更加高效

数据结构--》深入了解栈和队列,让算法更加高效

数据结构--》深入了解栈和队列,让算法更加高效

数据结构--》深入了解栈和队列,让算法更加高效

数据结构--》深入了解栈和队列,让算法更加高效

队列的基本概念

        队列是一种线性数据结构,具有先进先出(FIFO)的特点。与栈不同,队列只允许在队尾插入元素,在队头删除元素。队列通常用于需要按照时间顺序处理事物的场合,例如多任务并发处理或者打印机缓存任务等,它们按照顺序依次加入队列,并按照先进先出的顺序进行处理。

队列的基本操作如下:

InitQueue(&Q):初始化队列,构造一个空队列Q。

DestroyQueue(&Q):销毁队列。销毁并释放队列Q所占用的内存空间。

EnQueue(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。

DeQueue(&Q,&x):出队,若队列Q非空,删除对头元素,并用x返回。

GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x。

回顾重点,其主要内容整理成如下内容:  

数据结构--》深入了解栈和队列,让算法更加高效

队列的顺序和链式实现

队列可以用数组或链表等数据结构实现,分别称为顺序队列链式队列

顺序队列是基于数组的实现,使用一个数组来存储队列中的元素,使用头尾指针分别指向队列的头部和尾部。新元素插入到队列尾部,旧元素从队列头部删除,每次插入或删除元素后需要更新头尾指针。缺点是当队列元素个数达到数组容量时,需要进行数据搬移,时间复杂度为 O(n)。以下是一个 C++ 语言实现的顺序队列的简单示例代码:

#include <iostream>
using namespace std;

const int MAXSIZE = 100; // 队列的最大容量
int queue[MAXSIZE]; // 用数组实现队列
int head = 0, tail = 0; // 头尾指针

// 向队列尾部插入元素
void enqueue(int x) {
    if (tail == MAXSIZE) { // 队列已满
        cout << "Error: Queue is full!" << endl;
        return;
    }
    queue[tail++] = x; // 将新元素添加到队列尾部,同时更新尾指针
}

// 从队列头部删除元素
void dequeue() {
    if (head == tail) { // 队列为空
        cout << "Error: Queue is empty!" << endl;
        return;
    }
    head++; // 更新头指针,删除队首元素
}

// 获取队头元素
int getFront() {
    if (head == tail) { // 队列为空
        cout << "Error: Queue is empty!" << endl;
        return -1;
    }
    return queue[head]; // 返回队首元素
}

// 判断队列是否为空
bool isEmpty() {
    return head == tail; // 头尾指针相等时,队列为空
}

int main() {
    enqueue(1);
    enqueue(2);
    enqueue(3);

    cout << "Front of Queue: " << getFront() << endl;

    dequeue();
    dequeue();

    cout << "Front of Queue: " << getFront() << endl;

    return 0;
}

数据结构--》深入了解栈和队列,让算法更加高效

需要注意的是,在顺序队列中,每次删除元素时并没有真正将元素从数组中移除,而是单纯地将头指针向后移动。因此,当头指针后面有很多无用元素时,需要调整数组内部的元素位置,以节省内存空间。

回顾重点,其主要内容整理成如下内容:  

数据结构--》深入了解栈和队列,让算法更加高效

链式队列是基于链表的实现,使用一个链表来存储队列中的元素,使用头指针指向队首节点,尾指针指向队尾节点。新元素插入到链表尾部,旧元素从链表头部删除,每次插入或删除元素只需操作指针即可,无需进行数据搬移。链式队列相对于顺序队列的优点是没有容量限制,但由于链表需要额外的指针存储,空间开销较大一些。 以下是一个 C++ 语言实现的顺序队列的简单示例代码:

#include <iostream>
using namespace std;

struct Node {
    int data;
    Node* next;
};

Node* head = NULL; // 头指针指向队列头部
Node* tail = NULL; // 尾指针指向队列尾部

// 向队列尾部插入元素
void enqueue(int x) {
    Node* newNode = new Node;
    newNode->data = x;
    newNode->next = NULL;

    if (tail == NULL) { // 队列为空
        head = tail = newNode;
        return;
    }
    tail->next = newNode; // 将新节点添加到队列尾部
    tail = newNode; // 更新尾指针
}

// 从队列头部删除元素
void dequeue() {
    if (head == NULL) { // 队列为空
        cout << "Error: Queue is empty!" << endl;
        return;
    }
    Node* temp = head;
    head = head->next; // 更新头指针
    if (head == NULL) { // 如果队列中只有一个元素,删除后需要更新尾指针
        tail = NULL;
    }
    delete temp;
}

// 获取队头元素
int getFront() {
    if (head == NULL) { // 队列为空
        cout << "Error: Queue is empty!" << endl;
        return -1;
    }
    return head->data;
}

// 判断队列是否为空
bool isEmpty() {
    return head == NULL; // 头指针为空时,队列为空
}

int main() {
    enqueue(1);
    enqueue(2);
    enqueue(3);

    cout << "Front of Queue: " << getFront() << endl;

    dequeue();
    dequeue();

    cout << "Front of Queue: " << getFront() << endl;

    return 0;
}

需要注意的是,在链式队列中,每次删除元素时需要注意特殊情况,比如队列中只有一个元素的情况。还需要注意内存泄漏问题,每次删除元素后需要释放对应节点的内存空间。 

数据结构--》深入了解栈和队列,让算法更加高效

回顾重点,其主要内容整理成如下内容:  

数据结构--》深入了解栈和队列,让算法更加高效

双端队列的介绍:双端队列(deque)是一种可以在队列两端进行插入和删除操作的数据结构。它可以被看作是两个栈拼接而成,因此常常被称为“双端栈”。

数据结构--》深入了解栈和队列,让算法更加高效

回顾重点,其主要内容整理成如下内容:  

数据结构--》深入了解栈和队列,让算法更加高效文章来源地址https://www.toymoban.com/news/detail-497989.html

到了这里,关于数据结构--》深入了解栈和队列,让算法更加高效的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【数据结构】我家三岁表弟都明白的栈和队列,你不会不了解吧?

    【数据结构】我家三岁表弟都明白的栈和队列,你不会不了解吧?

    🧑‍💻作者: @情话0.0 📝专栏:《数据结构》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢!   栈是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但是对其限定该线性表只能在某一端进行插入或

    2024年01月24日
    浏览(11)
  • 【数据结构和算法】---栈和队列的互相实现

    【数据结构和算法】---栈和队列的互相实现

    具体题目可以参考 LeetCode 232. 用栈实现队列 首先要想到的是,队列是一种 先进先出 的结构,而栈是一种 先进后出 的结构。依此 我们可以定义两个栈结构来模拟先进先出 ,既然要定义两个栈,那么为了方便调用,我们可以将这两个栈结构定义在一个结构体中,如下: 实现

    2024年02月03日
    浏览(13)
  • 数据结构与算法——栈和队列<也不过如此>

    数据结构与算法——栈和队列<也不过如此>

    📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段, 因为最近参加新星计划算法赛道(白佬),所以加快了脚步,果然急迫感会增加动力 ——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的 📖作者主页:king南星 📖

    2024年01月23日
    浏览(13)
  • 深入了解队列:探索FIFO数据结构及队列

    深入了解队列:探索FIFO数据结构及队列

    之前介绍了栈:探索栈数据结构:深入了解其实用与实现(c语言实现栈) 那就快马加鞭来进行队列内容的梳理。队列和栈有着截然不同的工作方式,队列遵循先进先出(FIFO)的原则,在许多场景下都表现出强大的效率和实用性 源码可以来我的github进行查找:Nerosts/just-a-tr

    2024年02月03日
    浏览(15)
  • 第一百二十八天学习记录:数据结构与算法基础:栈和队列(上)(王卓教学视频)

    第一百二十八天学习记录:数据结构与算法基础:栈和队列(上)(王卓教学视频)

    1、栈和队列是两种常用的、重要的数据结构 2、栈和队列是限定插入和删除只能在表的“端点”进行的线性表 线性表可以在任意一个位置插入和删除,栈只能在最后位置插入和删除 只能删除第一个元素 栈和队列是线性表的子集(是插入和删除位置受限的线性表)

    2024年02月13日
    浏览(16)
  • 青岛大学_王卓老师【数据结构与算法】Week05_01_栈和队列的定义和特点1_学习笔记

    青岛大学_王卓老师【数据结构与算法】Week05_01_栈和队列的定义和特点1_学习笔记

    本文是个人学习笔记,素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享, 另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权,请留言作删文处理。 课程视频链接: 数据结构与算法基础–第05周01–3.1栈和队列的定义和特点

    2024年02月15日
    浏览(13)
  • 【数据结构】栈和队列(队列篇)

    【数据结构】栈和队列(队列篇)

    上期我们已经学习了数据结构中的栈,这期我们开始学习队列。 目录 1.队列的概念及结构 2.队列的实现 队列结构体定义 常用接口函数 初始化队列 队尾入队列 队头出队列 获取队列头部元素、 获取队列队尾元素 获取队列中有效元素个数 检测队列是否为空 销毁队列 3.循环队

    2024年02月13日
    浏览(9)
  • [数据结构】栈和队列

    [数据结构】栈和队列

    目录 1.栈 1.1概念 1.2 栈的使用 1.3.栈的模拟实现 2.队列 2.1概念 2.2队列的使用 2.3队列的模拟实现 2.4 循环队列 2.5双端队列   栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素

    2024年02月07日
    浏览(14)
  • 数据结构:栈和队列

    数据结构:栈和队列

    朋友们、伙计们,我们又见面了,本期来给大家解读一下栈和队列方面的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数据结构专栏:数据结构 个 人 主 页 :  stackY、 目录 前言:  1.栈 1.1栈的

    2024年02月06日
    浏览(12)
  • 栈和队列【数据结构】

    栈和队列【数据结构】

    2024年02月16日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包