目次
シーケンシャルスタック内の要素のジェネリックタイプを設定します。
ソース ファイル (SqStack) 内の関数 function の具体的な実装:
導入:
データ構造学習ディレクトリ:
データ構造系列学習(2) - 系列テーブル(Contiguous_List)
データ構造シリーズの学習 (3) - 単一リンクリスト (Linked_List)
データ構造シリーズ学習(5) - 二重連結リスト(Double_Linked_List)
前回の記事では二重リンクリストについて学び、それをコードで実装しましたが、この記事では古典的なデータ構造であるスタックについて理解し、学び、それをコードを使って実装します。
勉強:
ヤン・ウェイミン氏の「データ構造(C言語編)」では、スタックは次のように定義されています。
スタック (スタック) は、テーブルの最後でのみ挿入または削除操作に制限された線形テーブルです。したがって、スタックの場合、テーブルの端は特別な意味を持ち、これをスタックの先頭 (top) と呼び、それに応じてテーブルの先頭をスタックの底部 (bottom) と呼びます。要素のない空のリストは空スタックと呼ばれます。
スタックは特殊な種類の線形テーブルであり、データは一方の端からのみ入力し、一方の端からのみ出力できます。メスシリンダーに水を注ぐのと同じように、水を層として考えると、メスシリンダーに最初に入る水の層はメスシリンダーの底、つまりスタックの底にあり、その層は最後にメスシリンダーに入る水の量は、メスシリンダーの先頭、スタックの最上部にあります。
たとえば、データのセットができたので、これら 5 つのデータを大きいデータから小さいデータの順にスタックにプッシュする必要があります。
初期状態:
プッシュ状態:
Stack(スタック)は、テーブルの最後への挿入と削除操作に限定された線形テーブルです。
実際、これは何も難しいことではなく、端的に言えば、配列表の去勢版です。
コード:
シーケンシャルスタック (12) に実装する必要がある関数:
初期化関数 (Init_Stack);
プッシュ機能(プッシュ);
スタック機能(ポップ);
スタックの最上位要素の値を取得します (Top)。
判定フル機能(IsFull);
空判定関数(IsEmpty);
検索機能(検索);
拡張機能(Inc);
クリア機能(クリア);
破壊機能(Destroy);
印刷機能 (表示);
有効長関数を取得します (Get_Length)。
ヘッダー ファイル (SqStack.h):
シーケンシャルスタックの初期サイズを設定します。
#define LIST_INIT_SIZE 10//初始大小
シーケンシャルスタック内の要素のジェネリックタイプを設定します。
typedef int ELEM_TYPE;
構造設計:
typedef struct Stack
{
ELEM_TYPE * base;//存储空间基址(用来接收malloc返回在堆上申请的连续空间块开始地址)
int top;//当前有效长度,且还可以表示下一个待插入位置的下标
int listsize;//当前总空间大小
}Stack,*PStack;
すべての関数の宣言:
//初始化
void Init_Stack(PStack st);
//入栈(队尾插入)
bool Push(PStack st,ELEM_TYPE val);
//出栈(队尾删除))
bool Pop(PStack st);
//获取栈顶元素值
ELEM_TYPE Top(PStack st);
//判空
bool IsEmpty(PStack st);
//判满
bool IsFull(PStack st);
//搜索
int Search(PStack st,ELEM_TYPE val);
//扩容
void Inc(PStack st);
//清空
void Clear(PStack st);
//销毁
void Destroy(PStack st);
//打印
void Show(PStack st);
//获取有效值个数
int Get_length(PStack st);
ソース ファイル (SqStack) 内の関数 function の具体的な実装:
初期化関数 (Init_Stack):
スタックのベースをヒープ領域に適用される初期サイズとスタック構造のサイズに設定し、次にスタックの要素数を表すトップの値を 0 に割り当て、初期スタック サイズを1 つは最初に定義したマクロ置換です。
void Init_Stack(PStack st)
{
assert(st != nullptr);
st->base = (ELEM_TYPE*) malloc(LIST_INIT_SIZE * sizeof(Stack));
st->top = 0;
st->listsize = LIST_INIT_SIZE;
}
プッシュ機能(プッシュ):
スタックにプッシュするには、まずスタックがいっぱいであると判断する必要があり、スタックがいっぱいの場合は容量を拡張し、その後、プッシュする要素をヒープ上の基本グループの先頭の添字位置に割り当てます。エリアの一番上に 1 を加えます。
bool Push(PStack st,ELEM_TYPE val)
{
assert(st != nullptr);
if(IsFull(st)){
Inc(st);
}
st->base[st->top] = val;
st->top++;
return true;
}
スタック機能(ポップ):
スタックをポップするときは、まずスタックが空であるかどうかを判断し、スタックが空の場合は直接 false を返し、空でない場合は次の方法でスタック内の要素数を直接減らします。 1.
bool Pop(PStack st)
{
assert(st != nullptr);
if(IsEmpty(st)){
return false;
}
st->top--;
return true;
}
スタックのトップ要素関数を取得します (Top):
ここでは、ジェネリック型の基本グループの先頭 1 の添字の要素を直接返すことができます (配列と同様)。
ELEM_TYPE Top(PStack st)
{
assert(st != nullptr);
return st->base[st->top-1];
}
空判定関数(IsEmpty):
スタック内の要素の数が 0 の場合、スタックは空です。
bool IsEmpty(PStack st)
{
assert(st != nullptr);
return st->top == 0;
}
判定フル機能(IsFull):
スタック内の要素数がスタックの空間サイズと等しい場合、スタックがフルであると判断されます。
bool IsFull(PStack st)
{
assert(st != nullptr);
return st->top == st->listsize;
}
検索機能(検索):
順次検索と同様に、スタック内の要素を走査するための i 添字を定義します。探している値が基本グループの i 添字に対応する要素と等しい場合、この要素の添字を返します。見つからない場合は、その後、-1 を返します。
int Search(PStack st,ELEM_TYPE val)
{
assert(st != nullptr);
for(int i = 0;i < st->top;i++){
if(val == st->base[i]){
return i;
}
}
return -1;
}
拡張機能(Inc):
realloc 関数を使用して、ヒープ領域に最初に適用されたベース領域グループのサイズを 2 倍にし、さらにスタック領域 (listsize) のサイズを 2 倍にします。
void Inc(PStack st)
{
assert(st != nullptr);
st->base = (ELEM_TYPE*) realloc(st->base,(st->listsize * sizeof(ELEM_TYPE)) * 2);
assert(st->base != nullptr);
st->listsize *= 2;
}
クリア機能(クリア):
スタック内の要素の数 (最上位) を 0 に直接割り当て、スタック内のすべての要素をクリアします。
void Clear(PStack st)
{
assert(st != nullptr);
st->top = 0;
}
デストロイ機能(Destroy):
malloc 関数で元々確保されていたヒープ領域の領域を直接解放し、スタックの要素数 (top) を 0 に代入し、スタック領域のサイズ (listsize) を 0 に代入します。
void Destroy(PStack st)
{
assert(st != nullptr);
free(st->base);
st->top = 0;
st->listsize = 0;
}
印刷機能(表示):
ループを定義します。ループ条件は i < top で、スタック内のすべての要素を出力し、スタック内の要素の数 (top) とスタックの合計スペース (listsize) も出力します。
void Show(PStack st)
{
assert(st != nullptr);
for(int i = 0;i < st->top;i++){
printf("%3d",st->base[i]);
}
printf("\n");
printf("栈中的元素个数top为:%d\n",st->top);
printf("栈目前的总大小listsize为:%d\n",st->listsize);
}
有効長の取得関数 (Get_Length):
有効な値の数を記録する count 整数値を定義し、ループを定義し、ループが実行されるたびに count に 1 を加えて、関数の戻り値を count に設定します。
int Get_length(PStack st)
{
assert(st != nullptr);
int count = 0;
for(int i = 0;i < st->top;i++){
count++;
}
return count;
}
テスト:
テスト初期化関数、印刷関数:
#include<cstdio>
#include<cassert>
#include<cstdlib>
#include "SqStack.h"
int main()
{
Stack stack;
Init_Stack(&stack);
for(int i = 0;i < 100;i++){
Push(&stack,i + 1);
}
printf("在栈上的原始数据为:\n");
Show(&stack);
/*
此处添加其他测试功能代码...
*/
return 0;
}
操作結果:
プッシュ機能と拡張機能をテストします。
Push(&stack,11);
Show(&stack);
操作結果:
図に示すように、スタック領域がいっぱいになると、拡張機能によって合計サイズが元の 10 パラダイムから 2 倍の 20 パラダイムに拡張されます。
スタック関数をテストします。
printf("经过出栈操作之后:\n");
Pop(&stack);
Show(&stack);
操作結果:
テストクリア機能:
printf("\n经过清空操作之后:\n");
Clear(&stack);
Show(&stack);
操作結果:
テスト破壊関数:
printf("经过销毁操作之后:\n");
Destroy(&stack);
Show(&stack);
操作結果:
有効長の取得関数をテストします。
要約:
シーケンス スタックは比較的単純です。実際、これはシーケンス テーブルの去勢バージョンです。スタックのデータ構造の原則は先入れ後出しであるため、スタック操作はシーケンス テーブルの末尾挿入操作となります。私たちのスタック この操作は、シーケンス テーブルの末尾削除操作です。シーケンス テーブルの構造定義を変更し、それに対応して他の関数に小さな変更を加えるだけで済み、全体的な難易度は低くなります。