数据结构:栈和队列解析

目录

引言

一、栈

1.1 概念

1.2 操作

1.3 实现

Stack.h

Stack.cpp

1.4 应用场景

二、队列

2.1 概念

2.2 操作

 2.3 实现

Queue.h

Queue.cpp

1.4 应用场景

三、栈和队列的比较

四、总结


引言

在上一篇文章中给读者介绍了数据结构中较为简单的顺序表链表,此篇文章介绍的是在其基础上衍生的队列,四种结构均为线性结构。

一、栈

1.1 概念

栈是一种具有后进先出(Last-In-First-Out,LIFO)特性的线性数据结构。想象一下,你有一堆书放在桌子上,每当你放下一本书时,它会被放在最顶部。当你需要取出一本书时,你只能从最顶部开始取。这就是栈的工作方式。

或者说一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则。

1cee7c59dc5b4e51ab9793e8957e6592.png

1.2 操作

  • Push:将元素压入栈顶。
  • Pop:从栈顶弹出元素。
  • Top:返回栈顶元素的值。
  • IsEmpty:检查栈是否为空。

1.3 实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些,不过实际应用需要更加灵活的结构,一般使用动态栈,笔者所实现的也是动态方式。

Stack.h

#ifndef STACK_STACK_H
#define STACK_STACK_H

#include <cstddef>

typedef int STDataType;

class Stack {
private:
    STDataType *_data; //动态开辟栈空间
    size_t _top;        //指向栈顶元素的下一个位置
    size_t _capacity;   //栈的容量
public:
    //构造函数初始化内部属性并开辟动态空间
    explicit Stack(size_t capacity = 4);

    //析构函数释放开辟内存
    ~Stack();

    //进栈操作
    void push(STDataType value);

    //出栈操作
    void pop();

    //判断栈是否为空
    bool isEmpty();
};

#endif //STACK_STACK_H

Stack.cpp

#include "Stack.h"

// 构造函数初始化内部属性并开辟动态空间
Stack::Stack(size_t capacity) {
    _data = new STDataType[capacity];
    _top = 0;
    _capacity = capacity;
}

// 析构函数释放开辟内存
Stack::~Stack() {
    delete[] _data;
}

// 进栈操作
void Stack::push(STDataType value) {
    if (_top == _capacity) {
        // 栈满时扩展容量
        size_t newCapacity = _capacity * 2;
        STDataType* newData = new STDataType[newCapacity];
        for (size_t i = 0; i < _capacity; ++i) {
            newData[i] = _data[i];
        }
        delete[] _data;
        _data = newData;
        _capacity = newCapacity;
    }
    _data[_top++] = value;
}

// 出栈操作
void Stack::pop() {
    if (_top > 0) {
        --_top;
    }
}

// 判断栈是否为空
bool Stack::isEmpty() {
    return (_top == 0);
}

1.4 应用场景

  • 函数调用:栈用于存储函数调用的上下文信息,包括局部变量、返回地址等。
  • 括号匹配:栈可以用于检查表达式中的括号是否匹配。
  • 浏览器历史记录:浏览器使用栈来跟踪访问的网页,允许用户使用"后退"按钮返回上一个页面。

二、队列

2.1 概念

队列是一种具有先进先出First-In-First-Out,FIFO)特性的线性数据结构。可以想象为排队等候的人们,先到先得,后到后得。

或者说队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)特性。

入队列:进行插入操作的一端称为队尾

出队列:进行删除操作的一端称为队头

af261a5bc67e4768b23c3aebdbc549d3.png

2.2 操作

  • Enqueue:将元素添加到队列的末尾。
  • Dequeue:从队列的前端移除元素。
  • Front:返回队列的第一个元素。
  • IsEmpty:检查队列是否为空。

 2.3 实现

Queue.h

#ifndef QUEUE_QUEUE_H
#define QUEUE_QUEUE_H

#include <cstddef>

typedef int QDataType;

class Queue {
private:
    struct Node {
        QDataType data;
        Node* next;
        Node(QDataType value) : data(value), next(nullptr) {}
    };

    Node* _front;   // 队列的前端
    Node* _rear;    // 队列的后端

public:
    // 构造函数初始化内部属性
    Queue();

    // 析构函数释放内存
    ~Queue();

    // 入队操作
    void enqueue(QDataType value);

    // 出队操作
    void dequeue();

    // 返回队列的第一个元素
    QDataType front();

    // 判断队列是否为空
    bool isEmpty();
};

#endif //QUEUE_QUEUE_H

Queue.cpp

#include "Queue.h"

Queue::Queue() : _front(nullptr), _rear(nullptr) {}

Queue::~Queue() {
    while (_front != nullptr) {
        Node* temp = _front;
        _front = _front->next;
        delete temp;
    }
}

void Queue::enqueue(QDataType value) {
    Node* newNode = new Node(value);
    if (_rear == nullptr) {
        // 如果队列为空,则新节点同时成为队列的前端和后端
        _front = newNode;
        _rear = newNode;
    } else {
        // 如果队列不为空,则将新节点添加到队列的后端
        _rear->next = newNode;
        _rear = newNode;
    }
}

void Queue::dequeue() {
    if (_front != nullptr) {
        // 删除队列的前端节点并更新_front指针
        Node* temp = _front;
        _front = _front->next;
        if (_front == nullptr) {
            // 如果队列为空,则更新_rear指针
            _rear = nullptr;
        }
        delete temp;
    }
}

QDataType Queue::front() {
    if (_front != nullptr) {
        // 返回队列的第一个元素值
        return _front->data;
    }
    // 队列为空时的处理,这里假设元素类型为int,可以根据实际情况进行修改
    return 0;
}

bool Queue::isEmpty() {
    // 判断队列是否为空
    return (_front == nullptr);
}

1.4 应用场景

  • 广度优先搜索(BFS):队列在BFS算法中用于管理待处理的节点。
  • 缓冲区管理:队列常用于处理和管理输入/输出请求,确保按照请求的顺序进行处理。
  • 多线程任务调度:队列可以用于管理多个线程之间的任务调度。

三、栈和队列的比较

虽然栈和队列在某些方面很相似(都是线性数据结构),但它们的主要区别在于数据的插入和删除方式。栈从一端进行插入和删除操作,而队列则分别从两端进行这些操作。

性能方面,栈和队列的插入和删除操作的时间复杂度都是O(1),即常数时间。但是,对于栈和队列的其他操作,如访问特定元素或搜索特定元素,其时间复杂度可能会更高,取决于实现方式。

四、总结

栈和队列是计算机科学中重要的数据结构,它们在算法和编程中被广泛使用。栈具有后进先出的特性,适用于函数调用、括号匹配等场景。而队列则具有先进先出的特性,适用于广度优先搜索、任务调度等场景。

理解栈和队列的原理和特性,以及它们的应用场景,对于成为一名优秀的程序员至关重要。希望本文对读者有所帮助,进一步拓宽对数据结构的认识和理解。

猜你喜欢

转载自blog.csdn.net/weixin_57082854/article/details/131710207
今日推荐