目次
1. コンセプト
1. スタックの定義
スタックは、挿入 と 削除がリストの最後 までに 制限 さ れる線形リスト です 。スタックは、 後入れ先出し (Last In First Out) 線形リスト、または略して LIFO とも呼ばれます。
2. スタックのトップ
スタック は線形リストであり、 挿入 と 削除が可能な 端を スタックの先頭と呼びます。
3. スタックの一番下
スタックの最上部の 反対側 、もう一方の端はスタックの最下部 と呼ばれます 。実際、スタックの最下部の要素を気にする必要はありません。
2. インターフェース
1. 書き込み可能なインターフェース
1) データはスタックにプッシュされます
スタックの挿入操作は プッシュと呼ばれ、プッシュまたはプッシュとも呼ばれます。次の図に示すように、これは 3 つのプッシュ操作を表します。
2) データポップ
スタックの削除操作は スタックポップと呼ばれます。次の図に示すように、これは 2 つのポップ操作を表します。
3) スタックをクリアする
次の図に示すように、スタックが空になるまでスタックをポップし 続けます 。
2. 読み取り専用インターフェイス
1) スタックの先頭データを取得する
スタックの場合、 取得できるのは先頭の データのみであり、その他のデータは通常サポートされません。
2) スタック要素数を取得する
スタック要素の数は通常、追加の変数に格納され、スタックにプッシュされる と1 ずつ増加し、スタックからポップアウトされると 1 ずつ減少します 。この方法では、スタック要素を取得するときにスタック全体を走査する必要はありません。時間計算量 �(1)O(1) のスタック要素の数を取得します。
3) スタック空判定
スタック要素の数が 0 の場合、それは空のスタックであり、空の スタックではポップ操作は許可されません 。
3. スタックの基本動作
空のスタックを作成します: CreateStack (len)
スタッククリア:ClearStack(S)
スタックが空かどうかを判断します: EmptyStack (S)
スタックがいっぱいかどうかを判断します: FullStack (S)
要素をスタックにプッシュします: PushStack (S,x)
要素ポップ:PopStack(S)
スタックの最上位要素を取得します: GetTop (S)
4.シーケンシャルスタックの実装
1. データ構造の定義
C言語では 配列として表現されるシーケンステーブルの場合、 スタックを定義する
前に、 1) スタックデータの格納方法とデータ型、
2) スタックデータのサイズを 考慮する必要があります。スタック、
3) スタックトップポインタ。
- スタック構造を定義できます 。C 言語の実装は次のとおりです。
typedef int datatype;
typedef struct node{ /*定义栈中数据元素的数据类型*/
datatype *data; /*用指针指向栈的存储空间*/
int maxlen; /*当前栈的最大元素个数*/
int top; /*指示栈顶位置(数组下标)的变量*/
}sqstack; /*顺序栈类型定义*/
2. スタックを作成する
C 言語の実装は次のとおりです。
sqstack* stack_create(int len)
{
sqstack *s;
if((s=(sqstack *)malloc(sizeof(sqstack)))==NULL)
{
puts("malloc failed");
return NULL;
}
if((s->data=(datatype *)malloc(len*sizeof(datatype)))==NULL)
{
puts("malloc failed");
return NULL;
}
s->maxlen=len;
s->top=-1;
return s;
}
3. スタックをクリアする
C 言語の実装は次のとおりです。
void stack_clear(sqstack* s)
{
s->top = -1;
}
4.スタックが空かどうかを確認します。
C 言語の実装は次のとおりです。
int stack_empty(sqstack* s)
{
return (s->top==-1 ? 1:0);
}
5. スタックが飽和しているかどうかを判断する
C 言語の実装は次のとおりです。
int stack_full(sqstack* s)
{
return (s->top==(s->maxlen-1) ? 1:0);
}
6. スタックにプッシュします
C 言語の実装は次のとおりです。
int stack_push(sqstack* s,datatype value)
{
if(s->top==s->maxlen-1){
puts("stack is full");
return -1;
}
s->data[s->top+1]=value;
s->top++;
return 1;
}
7.スタックから抜け出す
C 言語の実装は次のとおりです。
datatype stack_pop(sqstack* s)
{
s->top--;
return s->data[s->top+1];
}
8.スタックの最上位要素を取得する
C 言語の実装は次のとおりです。
datatype stack_top(sqstack* s)
{
return(s->data[s->top]);
}
9. malloc によって要求されたメモリを解放します。
C 言語の実装は次のとおりです。
void stack_free(sqstack *s)
{
free(s->data);
s->data=NULL;
free(s);
s=NULL;
}
スタック内のすべての要素を出力する例
C 言語の実装は次のとおりです。
sqstack.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node{
datatype *data;
int maxlen;
int top;
}sqstack;
extern sqstack* stack_create(int len);
extern int stack_empty(sqstack* s);
extern int stack_full(sqstack* s);
extern void stack_clear(sqstack* s);
extern int stack_push(sqstack* s,datatype value);
extern datatype stack_pop(sqstack* s);
extern datatype stack_top(sqstack* s);
extern void stack_free(sqstack *s);
#endif
sqstack.c
#include "sqstack.h"
sqstack* stack_create(int len)
{
sqstack *s;
if((s=(sqstack *)malloc(sizeof(sqstack)))==NULL)
{
puts("malloc failed");
return NULL;
}
if((s->data=(datatype *)malloc(len*sizeof(datatype)))==NULL)
{
puts("malloc failed");
return NULL;
}
s->maxlen=len;
s->top=-1;
return s;
}
int stack_empty(sqstack* s)
{
return (s->top==-1 ? 1:0);
}
int stack_full(sqstack* s)
{
return (s->top==(s->maxlen-1) ? 1:0);
}
void stack_clear(sqstack* s)
{
s->top = -1;
}
int stack_push(sqstack* s,datatype value)
{
if(s->top==s->maxlen-1){
puts("stack is full");
return -1;
}
s->data[s->top+1]=value;
s->top++;
return 1;
}
datatype stack_pop(sqstack* s)
{
s->top--;
return s->data[s->top+1];
}
datatype stack_top(sqstack* s)
{
return(s->data[s->top]);
}
void stack_free(sqstack *s)
{
free(s->data);
s->data=NULL;
free(s);
s=NULL;
}
test.c
#include "sqstack.h"
int main(int argc, const char *argv[])
{
sqstack *s;
int n=5;
s=stack_create(n);
stack_push(s,10);
stack_push(s,20);
stack_push(s,30);
stack_push(s,40);
stack_push(s,50);
stack_push(s,60);
while(!stack_empty(s))
{
printf("%d ",stack_pop(s));
}
putchar(10);
stack_clear(s);
stack_free(s);
return 0;
}
メイクファイル
CC = gcc
CFLAGS = -g -Wall
test:test.o sqstack.o
$(CC) $(CFLAGS) -o $@ $^
.PHONY:clean
clean:
rm test *.o
-g: シンボリック デバッグ ツール (GNU の gdb) に必要なシンボル情報を生成します。ソース コードをデバッグしたい場合は、このオプションを追加する必要があります。
-Wall: gcc のすべての有用なアラーム情報の発行が許可されていることを示します。
-c: リンクせずにコンパイルするだけで、ターゲットファイル「.o 」を生成します。
-o test: 出力ファイルをファイルに出力することを意味します
操作結果:
5. スタックのリンクリスト実装
1. データ構造の定義
リンク リストの場合、 スタックを定義する
前に、 1) スタック データの格納方法とスタック データのデータ型、2) スタックのサイズ、 3 ) スタックの先頭ポインタ、3) スタック データのデータ型、3)
スタック データのデータ型、3) スタック データのデータ型、
3) スタック データのデータ型、3) スタック データのデータ型
スタック構造を定義できます 。C 言語の実装は次のとおりです。
typedef int datatype;
typedef struct node{
datatype data;
struct node* next;
}listnode,*linklist;
2. スタックを作成する
C 言語の実装は次のとおりです。
linklist stack_create()
{
linklist s;
if((s=(linklist)malloc(sizeof(listnode)))==NULL){
puts("malloc failed");
return NULL;
}
s->next=NULL;
return s;
}
3. スタックをクリアする
C 言語の実装は次のとおりです。
void stack_clear(linklist s)
{
linklist p;
printf("clear:");
p=s->next;
while(p)
{
s->next=p->next;
printf("%d ",p->data);
free(p);
p=s->next;
}
putchar(10);
}
4.スタックが空かどうかを確認します。
C 言語の実装は次のとおりです。
int stack_empty(linklist s)
{
return (s->next==NULL ? 1:0);
}
5. スタックにプッシュします
C 言語の実装は次のとおりです。
int stack_push(linklist s,datatype value)
{
linklist p;
if((p=(linklist)malloc(sizeof(listnode)))==NULL)
{
puts("malloc failed");
return -1;
}
p->data = value;
p->next=s->next;
s->next = p;
return 0;
}
6.飛び出す
C 言語の実装は次のとおりです。
datatype stack_pop(linklist s)
{
linklist p;
datatype ret;
p=s->next;
s->next=p->next;
ret=p->data;
free(p);
p=NULL;
return ret;
}
7.スタックの最上位要素を取得します
C 言語の実装は次のとおりです。
datatype stack_top(linklist s)
{
return (s->next->data);
}
8. malloc によって要求されたメモリを解放します。
C 言語の実装は次のとおりです。
void stack_free(linklist s)
{
linklist p;
printf("free:");
p=s;
while(p)
{
s=s->next;
printf("%d ",p->data);
free(p);
p=s;
}
putchar(10);
}
スタック内のすべての要素を出力する例
C 言語の実装は次のとおりです。
リンクスタック.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node{
datatype data;
struct node* next;
}listnode,*linklist;
extern linklist stack_create();
extern int stack_empty(linklist s);
extern void stack_clear(linklist s);
extern int stack_push(linklist s,datatype value);
extern datatype stack_pop(linklist s);
extern datatype stack_top(linklist s);
extern void stack_free(linklist s);
#endif
リンクスタック.c
#include "linkstack.h"
linklist stack_create()
{
linklist s;
if((s=(linklist)malloc(sizeof(listnode)))==NULL){
puts("malloc failed");
return NULL;
}
s->next=NULL;
return s;
}
int stack_empty(linklist s)
{
return (s->next==NULL ? 1:0);
}
int stack_push(linklist s,datatype value)
{
linklist p;
if((p=(linklist)malloc(sizeof(listnode)))==NULL)
{
puts("malloc failed");
return -1;
}
p->data = value;
p->next=s->next;
s->next = p;
return 0;
}
datatype stack_pop(linklist s)
{
linklist p;
datatype ret;
p=s->next;
s->next=p->next;
ret=p->data;
free(p);
p=NULL;
return ret;
}
datatype stack_top(linklist s)
{
return (s->next->data);
}
void stack_clear(linklist s)
{
linklist p;
printf("clear:");
p=s->next;
while(p)
{
s->next=p->next;
printf("%d ",p->data);
free(p);
p=s->next;
}
putchar(10);
}
void stack_free(linklist s)
{
linklist p;
printf("free:");
p=s;
while(p)
{
s=s->next;
printf("%d ",p->data);
free(p);
p=s;
}
putchar(10);
}
test.c
#include "linkstack.h"
int main(int argc, const char *argv[])
{
linklist s;
s=stack_create();
stack_push(s,10);
stack_push(s,20);
stack_push(s,30);
stack_push(s,40);
stack_push(s,50);
stack_push(s,60);
#if 0
while(!stack_empty(s))
{
printf("%d ",stack_pop(s));
}
putchar(10);
#endif
// stack_clear(s);
stack_free(s);
return 0;
}
メイクファイル
CC = gcc
CFLAGS = -g -Wall
test:test.o linkstack.o
$(CC) $(CFLAGS) -o $@ $^
.PHONY:clean
clean:
rm test *.o
操作結果:
6. 2 つの実装の長所と短所
1. シーケンステーブルの実装
シーケンス テーブルを使用してスタックを実装する場合、スタックのプッシュ と ポップ の定数時間の複雑さ は低く、スタックのクリア操作はリンク リストの実装 と比較して O(1) で済みます 。唯一の欠点は、適用する必要があることです。事前に容量を確保し、容量が足りない場合は拡張が必要となります。拡張方法については本記事では触れませんので、「C/C++面接事例100選」(4) ベクトル拡張戦略を参照してください。
2. リンクリストの実装
リンクされたリストを使用してスタックを実装する場合、スタックのプッシュ と ポップの定数時間の複雑さ は若干高くなります。主な理由は、スタック要素が挿入されるたびにスペースを適用する必要があるためです。が削除され、スペースを解放する必要があり、 スタックのクリア 操作が O(n ) である場合、 スタックの先頭ポインタを直接 空に設定すると、メモリ リークが発生します。利点は、スペースを事前に割り当てる必要がなく、許容されるメモリ範囲内で、 シーケンス テーブルの制限なしにスタックにプッシュできることです。