データ構造系列学習(6) - 逐次スタック(Stack)

目次

導入:

勉強:

初期状態:

プッシュ状態: 

コード:

ヘッダー ファイル (SqStack.h):

シーケンシャルスタックの初期サイズを設定します。

シーケンシャルスタック内の要素のジェネリックタイプを設定します。

構造設計:

すべての関数の宣言:

ソース ファイル (SqStack) 内の関数 function の具体的な実装:

初期化関数 (Init_Stack):

プッシュ機能(プッシュ):

スタック機能(ポップ):

スタックのトップ要素関数を取得します (Top):

空判定関数(IsEmpty):

判定フル機能(IsFull): 

検索機能(検索):

拡張機能(Inc):

クリア機能(クリア):

デストロイ機能(Destroy):

印刷機能(表示):

有効長の取得関数 (Get_Length):

テスト:

テスト初期化関数、印刷関数:

プッシュ機能と拡張機能をテストします。

スタック関数をテストします。

テストクリア機能:

テスト破壊関数: 

 有効長の取得関数をテストします。

要約:


導入:

データ構造学習ディレクトリ:

データ構造シリーズ学習 (1) - データ構造入門

データ構造系列学習(2) - 系列テーブル(Contiguous_List) 

データ構造シリーズの学習 (3) - 単一リンクリスト (Linked_List) 

データ構造シリーズ学習 (4) - 循環リンクリスト 

データ構造シリーズ学習(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);

操作結果:

 有効長の取得関数をテストします。

要約:

シーケンス スタックは比較的単純です。実際、これはシーケンス テーブルの去勢バージョンです。スタックのデータ構造の原則は先入れ後出しであるため、スタック操作はシーケンス テーブルの末尾挿入操作となります。私たちのスタック この操作は、シーケンス テーブルの末尾削除操作です。シーケンス テーブルの構造定義を変更し、それに対応して他の関数に小さな変更を加えるだけで済み、全体的な難易度は低くなります。

おすすめ

転載: blog.csdn.net/weixin_45571585/article/details/127801662