データ構造:シーケンシャルスタックとチェーンスタック

スタック

スタックは、Last In Fast Outを備えた線形テーブルであり、テーブルの最後に線形テーブルを挿入および削除するように制限されています。挿入と削除を許可する端は、スタックの最上位と呼ばれます。

スタック図

ここに写真の説明を挿入

スタック内およびスタック外の変更フォーム

スタックは線形テーブルの挿入位置と削除位置を制限し、要素が出入りする時間、つまりすべての要素がスタックにプッシュされない場合を制限しないため、最も高度なスタックの要素は必ずしも最後にポップされるとは限りません。 、スタックの最上位要素である限り、最初に移動する要素もポップできます。

たとえば、整数要素1、2、および3が順番にスタックにプッシュされ、スタック順序は次のようになります。

  • 最初のタイプ、1、2、3入力、次に3、2、1、出力、スタック順序321
  • 2番目のタイプ、1インチ、1アウト、2インチ、2アウト、3インチ、3アウト、スタック順序外123
  • 3番目のタイプ、1インチ、2インチ、2アウト、1アウト、3インチ、3アウト、スタック順序外213
  • 4番目のタイプ、1インチ、1アウト、2インチ、3インチ、3アウト、2アウト、スタック順序外132
  • 5番目のタイプ、1インチ、2インチ、2アウト、3インチ、3アウト、1アウト、スタック順序231

3つの要素に対して5つのスタック順序があります

スタックのシーケンシャルストレージ構造

スタックは線形テーブルの特殊なケースです。スタックのシーケンシャルストレージ構造は、実際には、シーケンシャルスタックと呼ばれる線形テーブルのシーケンシャルストレージを簡略化したものです。シーケンシャルスタック構造は次のとおりです。

typedef int ElemType;   /* ElemType类型根据实际情况而定,这里假设为int */  
typedef struct Stack
{
    
    
	Elemtype *elem;
	int top;   /* 用于栈顶指针 */
	int stacksize;  /* 栈的空间大小 */
}SqStack;

シーケンシャルスタックの初期化

  1. 初期スペースを開く
  2. トップを初期化
  3. スタックサイズを初期化します
void InitStack(PStack st)
{
    
    
	assert(st != NULL);  //确保st不为空指针
			
	st->elem = (ElemType*)malloc(sizeof(ElemType)*STACK_INIT_SIZE);
	st->stacksize = STACK_INIT_SIZE;
	st->top = -1;
}

シーケンシャルスタック拡張

  1. スペースを開く
  2. スタックサイズを更新
static void AppendStack(PStack st)//扩容
{
    
    
	assert(st != NULL);
	
	st->elem = (ElemType*)realloc(st->elem, st->stacksize + sizeof(ElemType)*STACKINCREMENT);
	st->stacksize += STACKINCREMENT;
}

シーケンシャルスタックのプッシュ(プッシュ)

ここに写真の説明を挿入
プッシュ操作の場合、実際には3つのことが行われます。

  1. スタックがいっぱいであると判断します
  2. スタックトップポインタープラス1
  3. 新しく挿入された要素をスタックの一番上のスペースに割り当てます
void Push(PStack st, ElemType val)
{
    
    
	assert(st != NULL);
		
	if (st->top == st->stacksize)  //判断栈满
	{
    
    
		AppendStack(st);
	}
	st->top++;  //栈顶指针加一
	st->elem[st->top] = val;  //将新插入元素赋值给栈顶空间
	
}

シーケンシャルスタックのポップ(ポップ)

スタックが空でない場合は、スタックの一番上の要素をeにポップし、一番上のポインターを1つ減らします。

int Pop(PStack st, ElemType *e)  // 若栈不为空,则弹出栈顶元素给e,栈顶指针减一
{
    
    
	assert(st != NULL);
		
	if (st->top >= 0)
	{
    
    
		*e = st->elem[st->top];
		st->top--;
		return 1;
	}
	return 0;	
}

シーケンシャルスタックの破壊

void Destory(PStack st)
{
    
    
	assert(st != NULL);

	free(st->elem);
	st->elem = NULL;
	st->stacksize = 0;
}

シーケンシャルスタックを空にする

void Clear(PStack st)
{
    
    
	assert(st != NULL);
	
	st->top = 0;
}

シーケンススタックが空です

bool IsEmpty(PStack st)
{
    
    
	assert(st != NULL);

	return st->top == -1;
}

シーケンシャルスタックの最上位要素を取得します

ElemType GetTop(PStack st)
{
    
    
	assert(st != NULL);
	return st->elem[st->top];
}

スタックの連鎖ストレージ構造

スタックのチェーンストレージ構造は、チェーンスタックと呼ばれるリンクリストモードでスタックを実装することです。
チェーンスタックは、次の図に示すように、スタックの最上位を単一のリンクリストの先頭に
ここに写真の説明を挿入
配置しますチェーンスタック構造は次のとおりです。

typedef struct StackNode  // 栈结点
{
    
    
	ElemType data;
	struct StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct LinkStack  // 链栈
{
    
    
	LinkStackPtr top;
	int count;
}LinkStack;

チェーンスタックの操作のほとんどは、挿入と削除を除いて、単一リンクリストの操作と同様です。

チェーンスタックのプッシュ(プッシュ)

要素値がeである新しいノードsがスタックにプッシュされ、topがスタックの最上位のポインターであるとすると、スタックへのプッシュの概略図は次のようになります。
ここに写真の説明を挿入

  1. 現在のスタックトップ要素を新しいノードの直後の後続要素に割り当てます
  2. 新しい要素を指すようにスタックのトップポインタを更新します
Status Push(LinkStack *LS, ElemType e)
{
    
    
	LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StacNode));
	s->data = e;
	
	s->next = LS->top; //将当前的栈顶元素赋值给新节点的直接后继
	LS->top = s;  //更新栈顶指针,使其指向新元素
	
	LS->count++;
	
	return OK;
}

チェーンスタックのポップ(ポップ)

変数pを使用して、削除するスタックの最上位ノードを格納するとします。

  1. 手順1に示すように、スタックの最上位ノードをpに割り当てます。
  2. 以下の手順2に示すように、スタックのトップポインタが1ビット下に移動します。
  3. ノードpを解放します

ここに写真の説明を挿入

//若栈不为空,则删除栈顶元素,用e返回其值,并返回OK;否则返回ERROR
Status Pop(LinkStack *S, ElemType *e)
{
    
    
	LinkStackPtr p;
	if(StackEmpty(*S))
	{
    
    
		return ERROR;
	}
	*e = S->top->next;
	
	p = S->top; //将栈顶结点赋值给p,如上图步骤1
	S->top = S->top->next;  //栈顶指针下移一位,如上图步骤2
	free(p);  //释放结点p
	S->count--;
	
	return OK;
}

シーケンシャルスタックとチェーンスタックの比較

シーケンシャルスタックとチェーンスタックのスタッキングとスタッキングの時間の複雑さはO(1)です。スペースパフォーマンスのために、シーケンシャルスタックは事前に固定長を決定する必要があり、メモリスペースの浪費を引き起こす可能性がありますが、チェーンスタックには各要素にポインタフィールドが必要であるのに対し、チェーンスタックにはアクセスと検索が簡単であるという利点があります。ある程度のメモリオーバーヘッドが追加されますが、スタックの長さは柔軟に開発できます。したがって、それらの違いは、シーケンシャルリストとリンクリストの違いのようなものです。
スタックの使用中の要素の変更が予測できない場合、場合によっては小さい場合、場合によっては大きい場合は、チェーンスタックを使用するのが最適です。逆に、変更が制御可能な範囲内にある場合は、シーケンシャルスタックを使用できます。

おすすめ

転載: blog.csdn.net/huifaguangdemao/article/details/108348862