皆さんこんにちは、お久しぶりです!!!本当に懐かしいです!!!
データ構造とアルゴリズムのコラムを更新してから長い時間が経ちました。最近、Xiao Yalan は多くの新しい知識を学びました。ステーション C の友達と共有するのが待ちきれません。次に、スタックの世界に入りましょう
スタック
スタックの概念と構造
スタック: 固定端の要素の挿入と削除のみを許可する特別な線形リスト。
データの挿入および削除操作が実行される端をスタックの最上位と呼び、もう一方の端をスタックの最下位と呼びます。
スタック内のデータ要素は、LIFO (Last In First Out) の原則に従います。
スタックのプッシュ: スタックの挿入操作はプッシュ/プッシュ/プッシュと呼ばれ、受信データはスタックの先頭にあります。
ポッピング: スタックの削除操作はポッピングと呼ばれます。出力データもスタックの最上位にあります。
いくつかの練習
1. スタックの初期状態は空です。ここで、要素 1、2、3、4、5、A、B、C、D、E を順番にスタックに入れて、順番にポップアウトします。要素がポップアウトされる順序は ( B)。
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA
2. プッシュ シーケンスが 1、2、3、4 で、プッシュ プロセス中にスタックをポップできる場合、次の不可能なポップ シーケンスは (C) です。
A 1、4、3、2
B 2、3、4、1
C 3,1,4,2
D 3,4,2,1
オプション A: アドバンスト 1、すぐにアウト 1、次にイン 2 3 4、次にアウト 4 3 2
オプション B: アドバンス 1、2、次にアウト 2、次にイン 3、アウト 3、イン 4、アウト 4、最後にアウト 1
オプション C: どのように入力および終了しても、そのような組み合わせは表示されません。理由は次のとおりです。 連続する 2 つの数字はない
D オプション: アドバンスト 1 2 3、次にアウト 3、次にイン 4、アウト 4、次にアウト 2、最後にアウト 1
スタックの実装
スタックの実装は通常、配列またはリンク リストを使用して実装できますが、比較的に配列の構造の方が優れています。配列の最後にデータを挿入するコストが比較的小さいためです。
次に、コードを使用して実装を開始します。
typedef int STDataType; typedef struct Stack { STDataType* a; int top;//栈顶 int capacity;//容量 }Stack;
これはすでに日常的な操作であり、構造体と typedef を使用してスタックを定義します。
スタックを初期化します。
// 初始化栈 void StackInit(Stack* pst) { assert(pst); pst->a = NULL; pst->top = 0; pst->capacity = 0; }
スタックを破棄します。
// 销毁栈 void StackDestroy(Stack* pst) { assert(pst); free(pst->a); pst->a = NULL; pst->top = pst->capacity = 0; }
スタックに:
ここでは三項演算子が使用されています
https://xiaoyalan.blog.csdn.net/article/details/128941939
https://xiaoyalan.blog.csdn.net/article/details/128993533
これは Xiao Yalan が書いたオペレーターの関連知識ポイントですので、興味のある方はご覧ください。
// 入栈 void StackPush(Stack* pst, STDataType x) { assert(pst); //扩容 if (pst->top == pst->capacity) { int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType)); if (tmp == NULL) { perror("realloc fail"); return; } pst->a = tmp; pst->capacity = newcapacity; } pst->a[pst->top] = x; pst->top++; }
スタックが空かどうかを確認します。
// 检测栈是否为空 bool StackEmpty(Stack* pst) { assert(pst); if (pst->top == 0) { return true; } else { return false; } }
もちろん、これは比較的低い書き方です。次の書き方を見てみましょう。
// 检测栈是否为空 bool StackEmpty(Stack* pst) { return pst->top==0; }
この書き方は非常に簡潔であり、本来あるべき機能も実現しています。
ポップ:
// 出栈 void StackPop(Stack* pst) { assert(pst); assert(!StackEmpty(pst)); pst->top--; }
スタックの最上位要素を取得します。
// 获取栈顶元素 STDataType StackTop(Stack* pst) { assert(pst); assert(!StackEmpty(pst)); return pst->a[pst->top - 1]; }
スタック内の有効な要素の数を取得します。
// 获取栈中有效元素个数 int StackSize(Stack* pst) { assert(pst); return pst->top; }
スタック (スタック) はスタックとも呼ばれ、操作が制限された線形テーブルです。挿入と削除をリストの末尾のみに制限する線形リスト。この端はスタックの上部と呼ばれ、もう一方の端はスタックの底部と呼ばれます。新しい要素をスタックに挿入することは、プッシュ、プッシュ、またはプッシュとも呼ばれます。新しい要素をスタックの最上位要素の上に配置して、スタックの新しい最上位要素にすることです。スタックから要素を削除することもできます。アンスタックとは、スタックの最上位要素を削除し、隣接する要素がスタックの新しい最上位要素になるようにすることです。
この概念を理解するには、まず「スタック」の本来の意味を理解し、本質をつかむ必要があります。スタックとは、物品を保管したり乗客の宿泊場所であるが、倉庫や乗換駅にまで拡張できるため、コンピュータ分野に導入される際には、データを一時的に保管する場所を指すため、「入る」という言葉がある。スタックを終了します。
まず第一に、システムまたはデータ構造スタック内のデータ コンテンツの読み取りと挿入 (プッシュ) のプッシュとポップは、2 つの異なるものです。データを追加するのがプッシュ、データを削除するのがポップであり、これらの操作は制約インタフェースであるスタックの最上位、つまり最下位アドレスからしか実行できませんが、スタック内のデータを読み出すのはカジュアルであり、インターフェースの制約などはありません。多くの人がこの概念を誤解しているため、スタックについて混乱しています。システム スタックは、コンピュータ アーキテクチャにおけるコンポーネント間の対話メディア領域、つまり CPU とメモリ間の通信チャネルの役割も果たします。CPU は、システムによって指定されたスタック エントリからのみ線形に読み取り、実行します。独自のアプリケーション プログラムの命令を、鮮やかな言葉で説明すると、パイプライン (パイプライン、パイプライン) です。CPU の内部相互作用の詳細については、EU と BIU の概念の紹介を参照してください。
データ構造としてのスタックは、一方の端でのみ挿入および削除操作を実行できる特殊な線形テーブルです。データは後入れ先出しの原則に従って保存され、最初に入力されたデータはスタックの一番下にプッシュされ、最後のデータはスタックの一番上に置かれます。スタックの先頭からポップされます (最後のデータが最初に読み出されます)。スタックにはメモリ機能があり、スタックの挿入や削除の際にスタックのボトムポインタを変更する必要がありません。
スタックは、同じ端での挿入と削除を可能にする特別な線形リストです。挿入および削除操作が可能な端をスタックの上部 (top)、もう一方の端をスタックの底部 (bottom) と呼び、スタックの下部は固定され、スタックの上部はフローティングになります。スタック内の要素の数がゼロの場合、それは空のスタックと呼ばれます。一般に挿入をプッシュ(PUSH)、削除をポップ(POP)と呼びます。スタックは先入れ後出しリストとも呼ばれます。
スタックは、関数が呼び出されるときにブレークポイントを保存するために使用でき、スタックは再帰を実行するときに使用されます。上記の定義は古典的なコンピューターサイエンスにおける解釈です。
コンピュータ システムでは、スタックは上記の特性を持つ動的メモリ領域です。プログラムはデータをスタックにプッシュしたり、スタックの最上部からデータをポップしたりできます。i386 マシンでは、スタックの最上位は esp と呼ばれるレジスタによって配置されます。スタックをプッシュする操作はスタックの先頭のアドレスを減らし、ポップする操作はスタックの先頭のアドレスを増やします。
スタックはプログラムの動作において重要な役割を果たします。最も重要なことは、関数呼び出しに必要なメンテナンス情報がスタックに保存されることです。これはスタック フレームまたはアクティブ レコードと呼ばれることがよくあります。スタック フレームには通常、次の情報が含まれます。
1. 関数
2の戻りアドレスとパラメータ。一時変数: 関数の非静的ローカル変数や、コンパイラーによって自動的に生成されるその他の一時変数が含まれます。
このコードの機能をテストします。
void testStack1()
{
Stack st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
printf("栈顶元素:%d\n", StackTop(&st));
printf("栈中元素个数:%d\n", StackSize(&st));
StackPop(&st);
printf("栈顶元素:%d\n", StackTop(&st));
StackPush(&st, 5);
StackPush(&st, 6);
while (!StackEmpty(&st))
{
printf("栈顶元素:%d\n", StackTop(&st));
StackPop(&st);
}
StackDestroy(&st);
}
int main()
{
testStack1();
return 0;
}
ソースコードは次のとおりです。
Stack.h の内容:
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶
int capacity;//容量
}Stack;
// 初始化栈
void StackInit(Stack* pst);
// 销毁栈
void StackDestroy(Stack* pst);
// 入栈
void StackPush(Stack* pst, STDataType x);
// 出栈
void StackPop(Stack* pst);
// 获取栈顶元素
STDataType StackTop(Stack* pst);
// 获取栈中有效元素个数
int StackSize(Stack* pst);
// 检测栈是否为空
bool StackEmpty(Stack* pst);
Stack.c の内容:
#include"Stack.h"
// 初始化栈
void StackInit(Stack* pst)
{
assert(pst);
pst->a = NULL;
pst->top = 0;
pst->capacity = 0;
}
// 销毁栈
void StackDestroy(Stack* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
// 入栈
void StackPush(Stack* pst, STDataType x)
{
assert(pst);
//扩容
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
// 检测栈是否为空
bool StackEmpty(Stack* pst)
{
assert(pst);
if (pst->top == 0)
{
return true;
}
else
{
return false;
}
//return pst->top==0;
}
// 出栈
void StackPop(Stack* pst)
{
assert(pst);
assert(!StackEmpty(pst));
pst->top--;
}
// 获取栈顶元素
STDataType StackTop(Stack* pst)
{
assert(pst);
assert(!StackEmpty(pst));
return pst->a[pst->top - 1];
}
// 获取栈中有效元素个数
int StackSize(Stack* pst)
{
assert(pst);
return pst->top;
}
さて、Xiao Yalan が今日共有したスタックの知識はこれで終わりです。引き続きデータ構造とアルゴリズムを学習しましょう。!!