勤勉であり、誰も待たないように何年も費やすことを奨励してください
C/C++ ゲーム開発
こんにちは、ミナさん、Junxi_ です。引き続き基本的なデータ構造の内容を学習しましょう。今日はスタックとキューについて説明します。このブログでは最初にスタックについて説明し、次にキューについて説明します。また話しましょう
、くだらない話はやめて、今日の勉強を始めましょう!—
1.スタック
1. スタックの概念と構造
-
スタック: 固定端の要素の挿入と削除のみを許可する特別な線形リスト。データの挿入および削除操作が実行される端をスタックの最上位と呼び、もう一方の端をスタックの最下位と呼びます。スタック内のデータ要素は、LIFO (Last In First Out) の原則に従います。
-
スタックのプッシュ: スタックの挿入操作はプッシュ/プッシュ/プッシュと呼ばれ、受信データはスタックの先頭にあります。
ポッピング: スタックの削除操作はポッピングと呼ばれます。出力データもスタックの最上位にあります
-
プッシュでもポッピングでも、後入れ先出しの原則に従います。
2. スタックの実装
- スタックの実装は一般に配列またはリンク リストを使用して実装できますが、比較的に配列の構造の方が優れています。なぜなら、配列は最後にデータを挿入するために大きな代償を払う必要がないからです。
- リンクされたリストで実装されている場合、問題が発生します。スタックは実際には末尾の挿入によってスタックにプッシュされます。つまり、スタックにプッシュするときに毎回トラバースして末尾を見つける必要があるか、次のコマンドを使用する必要があります。双頭ループ リンク リストは末尾を見つけるために使用されますが、配列の連続性とランダム アクセスのサポートにより、リンク リストよりも便利であることは間違いありません。そこで、次のコンテンツでは配列を使ってスタック構造を実装していきます。
3. スタックの分類
- スタックは静的スタックと動的スタックに分けられます
静的スタック
// 下面是定长的静态栈的结构,实际中一般不实用
typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType a[N];
int _top; // 栈顶
int _capacity; // 容量
}Stack;
動的スタック
- ダイナミック スタックはダイナミック メモリ開発によって実現されており、ダイナミック メモリ変更をサポートしているため、実際のアプリケーションではダイナミック スタックの方が優れた選択肢であることは間違いありません。
typedef int STDataType;//方便以后修改栈中存储的数据类型
typedef struct Stack
{
STDataType* a;//数组
int top;//存放栈中有效元素的个数
int capacity;//栈的容量大小
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
//获取栈底元素
STDataType StackTail(Stack* ps);
4. ダイナミックスタックの実現
スタック初期化関数 StackInit
- データ構造がどのようなものであっても、最初に初期化する必要があります
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps);//断言
ps->a = NULL;//数组中还没有元素
//容量和有效元素都为0
ps->capacity = 0;
ps->top = 0;
}
プッシュ関数 StackPush
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
//判断是否还有空间
if (ps->capacity == ps->top)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//通过容量判断此时栈中有没有元素,如果没有元素就申请4个字节的空间,如果有容量,但容量不够时就把容量变为之前的2倍
STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity* sizeof(STDataType));
if (tmp == NULL)//判读开辟空间是否成功
{
perror("realloc failed");
exit(-1);
}
ps->a = tmp;//成功了就把这个新的空间给我们的a数组
ps->capacity = newCapacity;//容量也要做相应的动态变化
}
ps->a[ps->top] = data;//往栈中存元素
ps->top++;//有效元素++
}
- 動的メモリ管理の内容について十分に知らない方もいるかもしれません。私のブログを参照してください: [上級 C 言語] マスターすべき C/C++ のポイント - 動的メモリ管理 (1)
- ここでもう 1 つ言及しておく必要があります。なぜ malloc を使用せずに realloc を使用して領域を解放するのでしょうか。
- ここでは、Realloc をプレイする高度な方法をいくつか紹介します。
- realloc は動的に割り当てられたメモリ サイズを変更するために使用されることはわかっていますが、それに null ポインターを渡すと、その機能は malloc と同じになります。
スタック関数 StackPop
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
--ps->top;
}
- スタックから取り出すのは非常に簡単です。先頭を 1 だけ減らすだけです。配列は添字を介して配列のメンバーにアクセスするため、先頭が削減されると対応する要素は見つかりません。
スタックの最上位要素を取得する関数 StackTop
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
//有效元素为top,数组的下标得-1
return ps->a[ps->top-1];
}
- スタック内の要素は最後に挿入されるため、最後の要素がスタックの最上位要素になります。
スタック下部要素 StackTail を取得する
- スタックの一番下が必要になるのは一般的ではありません。これは、いくつかの特別な場合にのみ使用されます (後で説明する OJ の質問など)。
STDataType StackTail(Stack* ps)
{
assert(ps);
return ps->a[0];
}
- 要素は配列の末尾に挿入されるため、最初の要素がスタックの一番下の要素になります。
スタック内の有効な要素の数を取得する関数 StackSize
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
- 以前にプッシュされたかポップされたかにかかわらず、有効な要素の先頭を変更したため、返された先頭は有効な要素の数になります。
スタックが空かどうかを判定する関数 StackEmpty
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
- top には有効な要素が格納されるため、top が 0 かどうかを判断することでスタックが空かどうかを判断できます。
スタックを破棄する関数
// 销毁栈
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);//free掉动态开辟的数组
ps->a = NULL;//置空
ps->top = ps->capacity = 0;//把有效元素和容量全部清空
}
- メモリは動的に割り当てられるため、メモリの使用が終了したら、メモリ リークを防ぐために適用したメモリを解放する必要があります。
5. テストスタック
- 効果を試してみましょう
void TestStack1()
{
Stack ST;
StackInit(&ST);
StackPush(&ST, 10);
StackPush(&ST, 20);
StackPush(&ST, 30);
while (!StackEmpty(&ST))
{
printf("%d ", StackTop(&ST));
StackPop(&ST);
}
StackDestroy(&ST);
}
int main()
{
TestStack1();
return 0;
}
要約する
- 今日の内容はこれで終わりです 先ほどのシーケンスリストやリンクリストなどを理解できれば、スタックの内容は実はとても簡単です しっかり学びたい方はぜひやってみてください!!
- 質問がございましたら、コメント欄またはプライベート メッセージでお問い合わせください。また次回お会いしましょう。
新しいブロガーを作成するのは簡単ではありません。記事の内容が役立つと思われる場合は、離れる前にこの新しいブロガーをクリックするとよいでしょう。皆様の応援が更新の励みになります!!!
**(Ke Li はブロガーを 3 回連続でサポートするようお願いしています!!! 以下のコメントをクリックして「いいね」を押し、Ke Li を支援するために集めてください)**