目次
導入
前回の記事では比較的単純なデータ構造であるシーケンシャルリストとリンクリストについて紹介しましたが、今回はそこから派生するスタックとキューについて紹介します。これら4つの構造はすべて線形構造です。
1.スタック
1.1 コンセプト
スタックは、後入れ先出し (LIFO ) 特性を持つ線形データ構造です。テーブルの上に本の山があり、本を置くたびにその本が上に置かれると想像してください。本を取り出すときは、上からしか取り出すことができません。これがスタックの仕組みです。
言い換えれば、スタックは、一方の固定端でのみ要素の挿入と削除を許可する特殊な線形テーブルです。データの挿入および削除操作が実行される端をスタックの最上位と呼び、もう一方の端をスタックの最下位と呼びます。スタック内のデータ要素は、後入れ先出しの原則に従います。
1.2 操作
- Push : 要素をスタックの最上部にプッシュします。
- Pop : 要素をスタックの一番上からポップします。
- Top : スタックの最上位要素の値を返します。
- I sEmpty : スタックが空かどうかを確認します。
1.3 実装
スタックは通常、配列またはリンク リストを使用して実装できます。比較的言えば、配列の構造の方が優れています。しかし、実際のアプリケーションでは、より柔軟な構造が必要です。一般的には動的スタックが使用され、著者の実装も動的メソッドです。
スタック.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
スタック.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 応用シナリオ
- 関数呼び出し: スタックは、ローカル変数、戻りアドレスなどを含む関数呼び出しのコンテキスト情報を保存するために使用されます。
- 括弧の一致: スタックを使用して、式内の括弧が一致するかどうかを確認できます。
- ブラウザ履歴: ブラウザはスタックを使用して訪問した Web ページを追跡し、ユーザーが「戻る」ボタンを使用して前のページに戻ることができるようにします。
2、行列
2.1 コンセプト
キューは、先入れ先出し (FIFO) 特性を持つ線形データ構造です。それは、人々が列に並んで、先着順、後順、後順で待っていることを想像できます。
つまり、キューとは、一方からはデータを挿入し、もう一方からはデータを削除することしかできない特殊な線形テーブルであり、FIFO(先入れ先出し)の性質を持っています。
キューへ: 挿入操作の終わりをキューの終わりと呼びます。
キューの外: 削除操作の終わりはキューの先頭と呼ばれます
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
キュー.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 アルゴリズムで使用されます。
- バッファ管理: キューは入出力リクエストの処理と管理によく使用され、リクエストがリクエストされた順序で処理されるようにします。
- マルチスレッド タスク スケジューリング: キューを使用して、複数のスレッド間のタスク スケジューリングを管理できます。
3. スタックとキューの比較
スタックとキューはいくつかの点で似ていますが (どちらも線形データ構造です)、主な違いはデータの挿入方法と削除方法です。スタックは挿入と削除を一方の端から実行し、キューはこれらの操作を両端から実行します。
パフォーマンスの観点から見ると、スタックとキューの挿入および削除操作の時間計算量は O(1)、つまり一定時間です。ただし、特定の要素へのアクセスや特定の要素の検索など、スタックやキューに対するその他の操作の場合、実装によっては時間の複雑さが高くなる可能性があります。
4. まとめ
スタックとキューはコンピューター サイエンスにおける重要なデータ構造であり、アルゴリズムやプログラミングで広く使用されています。スタックには後入れ先出しの特性があり、関数呼び出しやブラケット マッチングなどのシナリオに適しています。キューには先入れ先出しの特性があり、幅優先検索やタスク スケジューリングなどのシナリオに適しています。
優れたプログラマになるには、スタックとキューの原理と特性、およびそれらのアプリケーション シナリオを理解することが重要です。この記事が読者の役に立ち、データ構造に関する知識と理解をさらに広げることができれば幸いです。