インタビュアーから「スタック」とは何かと尋ねられ、10枚の写真を描いて説明しました


著者| Li Xiaoyao

ソース|テクノロジーは夢をより大きくします(ID:TechDreamer)

スタックのコンセプト

スタックは、テーブルの一方の端でのみ動作するように制限されたデータ構造であり、スタックは先入れ先出しのデータ構造です。次の図に示すように、操作を許可する端をスタックのトップと呼び、許可されない端をスタックのボトムと呼びます。公演:

リンクリストについて説明する前に、リンクリストの終了ノードでのみ操作でき、新しいノードの挿入と最後のノードの削除のみが可能であり、このような限定的な「リンクリスト」 'はスタックと呼ばれるものです。

行き止まりのように、図に示すように、出口は1つだけあり、概念があります。


スタックのノード設計

スタックは、配列スタックとリンクリストスタックに分かれており、次のような違いがあります。

  • 配列スタックは、配列を使用して関数をシミュレートします。これは、より高速で便利です。

  • リンクされたリストスタックは、リンクされたリストのアイデアで設計されています。これは実装が比較的面倒ですが、安定していて間違いを犯しにくいものです。

  • リンクリストスタックは、静的リンクリストスタックと動的リンクリストスタックに分かれていますが、次のような違いがあります。

  • 静的リンクリストスタックの特定のスタックのスペースサイズは、特定のデータサイズを超える要素のストレージを超えることはできません。

  • ダイナミックスタックは、スペースを自動的に作成する方法で作成され、マシンのハードウェア要件とコンパイラーの制御を満たす限り、理論的には優れています。

配列スタック

スタックにデータ要素を格納するために、実際には連続ストレージスペースを使用します。これには、次の特性があります。

  1. ここでの連続性とは、物理的な連続性ではなく、論理的な連続性を指します。

  2. 記憶域内の要素の場所は、論理的な順序で格納されます。

例を挙げましょう。C言語の配列添え字はすべて0で始まり、スタックの使用に必要なスペースのサイズを見積もることが難しいため、空のスタックを初期化するときは、スタックの最大容量を設定しないでください。

最初にスタックの基本容量を設定します。STACK_プロセス中に、スタックスペースが足りない場合は、徐々に拡張されます。

STACK_INIT_SIZE(ストレージスペースの初期割り当て量)とSTACK_INCREMENT(ストレージスペースの割り当て増分)の2つの定数を設定すると、マクロの定義は次のようになります。

#define STACK_INIT_SIZE 1000 //数值可以根据实际情况确定
#define STACK_INCREMENT 10   //数值可以根据实际情况确定

スタックの定義は次のとおりです。

typedef struct      
{
    void *base; 
    void *top;
    int stackSize;
} SqSTACK;

  • baseはスタックの一番下のポインタを表します

  • topはスタックのトップポインターを表します

  • stackSizeは、スタックで現在使用可能な最大容量を表します

baseの値がNULLの場合、それはスタック構造が存在しないことを意味します; topの初期値はスタックの一番下を指しています、つまり、top = base;

新しい要素が挿入されるたびに、ポインターの先頭は1ずつインクリメントされます。それ以外の場合は、1ずつデクリメントされます。空でないスタックのトップポインターは、常にスタックのトップエレメントの次のポインターの上にあります

次の図は、データ要素とスタックの最上部にあるポインターの関係を示しています。


リンクリストスタック

スタックを設計する例として、リンクリストスタックの動的リンクリストスタックを取り上げます。

1つはスタックのノードです。2つの構造が設計されています。1つの構造Nodeは、図に示すように、データフィールドと次のポインタを含むノードを表します。

ノード

その中で、データはデータを表し、次のポインターは次のノードを指す次のポインターを表し、各ノードは次のポインターを介してリンクされます。

次に、私たちのデザインの焦点です。この限定的なデザインでは、常にスタックのトップを指すポインタートップと、要素の数を記録するためのカウンターカウントを含む追加の構造を追加する必要があります。

その主な機能は、図に示すように、許可された操作要素のポインタを設定し、スタックが空になるタイミングを決定することです。

スタック

ここでは、topとcountの組み合わせを使用しています。コードは次のように表現できます。

//栈的结点设计
//单个结点设计,数据和下一个指针
typedef struct node     
{
    int data; 
    struct node *next;
} Node;

上記のノードを使用してスタックを作成します。スタックは、ヘッドノードへのトップポインターとカウントのためにカウントされます。

typedef struct stack    
{
    Node *top;
    int count;
} Link_Stack;


スタックへのスタックの基本操作(スタックのプッシュ)

積み重ねの基本的な順序を次の図に示します。

プッシュ操作では、topが指すスペースを見つけ、新しいノードを作成し、新しいノードの次のポインターをtopポインターが指すスペースにポイントしてから、topポインターを転送して新しいノード、これはプッシュ操作です。

コードは次のように表現できます。

//入栈 push
Link_Stack *Push_stack(Link_Stack *p, int elem)
{
    if (p == NULL)
        return NULL;
    Node *temp;
    temp=(Node*)malloc(sizeof(Node));
    //temp = new Node;
    temp->data = elem;
    temp->next = p->top;
    p->top = temp;
    p->count++;
    return p;
}


栈的基本操作—出栈

ポップ操作は、スタックが空でないときに繰り返される操作です。null操作を実行し、スタックの一番上の要素を削除して、一番上のポインターを次に移動する必要があります。

コードは次のように表現できます。

//出栈 pop
Link_Stack *Pop_stack(Link_Stack *p)
{
    Node *temp;
    temp = p->top;
    if (p->top == NULL)
    {
        printf("错误:栈为空");
        return p;
    }
    else
    {
        p->top = p->top->next;
        free(temp);
        //delete temp;
        p->count--;
        return p;
    }
}


栈的基本操作—遍历

これは非常に一般的であり、デバッグするための必要な手段でもあります。

スタックの走査は比較的複雑ですが、スタックの特殊な性質により、一方の端でのみ操作が許可されるため、走査操作は常に逆の順序になります。

簡単に説明すると、プロセスは、スタックが空でない場合、ポインターが空(つまり、スタックの最後)を指すまで、スタックの一番上の要素から下に1回アクセスします。

コードは次のように表現できます。

//遍历栈:输出栈中所有元素
int show_stack(Link_Stack *p)
{
    Node *temp;
    temp = p->top;
    if (p->top == NULL)
    {
        printf("");
        printf("错误:栈为空");
        return 0;
    }
    while (temp != NULL)
    {
        printf("%d\t", temp->data);
        temp = temp->next;
    }
    printf("\n");
    return 0;
}


スタック配列とスタックリンクリストのコード実現

最後に、理解に役立つコードを使用します。

スタック配列

配列スタックは、スタックの実装をシミュレートするためのより高速な方法です。ここでは説明しません。

シミュレーションとは、実際のリンクリストデザインを使用する代わりに、配列をシミュレーション操作に使用することを意味します。

言い換えれば、これはシミュレーションタイプの操作であり、コードの構築、プロセスの分析にすばやく役立ち、対応する実装がより便利になります。

コードは次のとおりです。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxn 10000

//结点设计
typedef struct stack{
    int data[maxn];
    int top;
}stack;

//创建
stack *init(){
    stack *s=(stack *)malloc(sizeof(stack));
    if(s==NULL){
        printf("分配内存空间失败");
        exit(0);
    }
    memset(s->data,0,sizeof(s->data));
    //memset操作来自于库文件string.h,其表示将整个空间进行初始化
    //不理解可以查阅百度百科https://baike.baidu.com/item/memset/4747579?fr=aladdin
    s->top=0;     //栈的top和bottom均为0(表示为空)
    return s;
}

//入栈push
void push(stack *s,int data){
    s->data[s->top]=data;
    s->top++;
}

//出栈pop
void pop(stack *s){
    if(s->top!=0){
        s->data[s->top]=0;  //让其回归0模拟表示未初始化即可
        s->top--;
    }
}

//模拟打印栈中元素
void print_stack(stack *s){
    for(int n=s->top-1;n>=0;n--){
        printf("%d\t",s->data[n]);
    }
    printf("\n");   //习惯性换行
}

int main(){
    stack *s=init();
    int input[5]={11,22,33,44,55};  //模拟五个输入数据
    for(int i=0;i<5;i++){
        push(s,input[i]);
    }
    print_stack(s);
    /
    pop(s);
    print_stack(s);
    return 0;
}

コンパイル結果は次のとおりです。

スタックリスト

#include <stdio.h>
#include <stdlib.h>
//栈的结点设计
//单个结点设计,数据和下一个指针
typedef struct node     
{
    int data; 
    struct node *next;
} Node;
//利用上面的结点创建栈,分为指向头结点的top指针和计数用的count
typedef struct stack    
{
    Node *top;
    int count;
} Link_Stack;

//创建栈
Link_Stack *Creat_stack()
{
    Link_Stack *p;
    //p = new Link_Stack;
    p=(Link_Stack*)malloc(sizeof(Link_Stack));
    if(p==NULL){
        printf("创建失败,即将退出程序");
        exit(0);
    }
 else
 {printf("创建成功\n");
 }
    p->count = 0;
    p->top = NULL;
    return p;
}

//入栈 push
Link_Stack *Push_stack(Link_Stack *p, int elem)
{
    if (p == NULL)
        return NULL;
    Node *temp;
    temp=(Node*)malloc(sizeof(Node));
    //temp = new Node;
    temp->data = elem;
    temp->next = p->top;
    p->top = temp;
    p->count++;
    return p;
}

//出栈 pop
Link_Stack *Pop_stack(Link_Stack *p)
{
    Node *temp;
    temp = p->top;
    if (p->top == NULL)
    {
        printf("错误:栈为空");
        return p;
    }
    else
    {
   printf("\npop success");
        p->top = p->top->next;
        free(temp);
        //delete temp;
        p->count--;
        return p;
    }
}

//遍历栈:输出栈中所有元素
int show_stack(Link_Stack *p)
{
    Node *temp;
    temp = p->top;
    if (p->top == NULL)
    {
        printf("");
        printf("错误:栈为空");
        return 0;
    }
    while (temp != NULL)
    {
        printf("%d\t", temp->data);
        temp = temp->next;
    }
    printf("\n");
    return 0;
}

int main()
{ //用主函数测试一下功能
 int i;
    Link_Stack *p;
    p = Creat_stack();
    int n = 5;
    int input[6] = {10,20,30,40,50,60};
    /以依次入栈的方式创建整个栈//
    for(i=0;i<n;i++){
        Push_stack(p, input[i]);
    }
    show_stack(p);
    出栈///
    Pop_stack(p);
    show_stack(p);
    return 0;
}

コンパイル結果は次のとおりです。


スタックについてのまとめ

Stack-Itは、操作が制限された線形テーブルであり、数値システム変換、ブラケットマッチングチェック、式評価などに使用でき、問題をより簡単に解決できます。

今日のスタックの基本は以上です。次の号でお会いしましょう!

更多精彩推荐
☞CSDN 今日发布开源代码托管平台 CODE.CHINA
☞乘“峰”而上,聚生态之力共创软件产业新未来

☞腾讯微博即将关停,十年了,你用过吗?
☞Cognitive Inference:认知推理下的常识知识库资源、常识推理测试评估与中文实践项目索引
☞超详细 | 21张图带你领略集合的线程不安全
☞腾讯云区块链邀您参加2020腾讯全球数字生态大会
点分享点点赞点在看

おすすめ

転載: blog.csdn.net/csdnnews/article/details/108544140