1スタック
1.1 スタックの概念と構造
スタック: 固定端の要素の挿入と削除のみを許可する特別な線形リスト。データの挿入および削除操作が実行される端をスタックの最上位と呼び、もう一方の端をスタックの最下位と呼びます。スタック内のデータ要素は、LIFO (Last In First Out) の原則に従います。
スタックのプッシュ: スタックの挿入操作はプッシュ/プッシュ/プッシュと呼ばれ、受信データはスタックの先頭にあります。
ポッピング: スタックの削除操作はポッピングと呼ばれます。出力データもスタックの最上位にあります。
1.2 スタックの実装
スタックの実装は通常、配列またはリンク リストを使用して実装できますが、比較的に配列の構造の方が優れています。配列の最後にデータを挿入するコストが比較的小さいためです。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶
int capacity;//容量
}ST;
//初始化栈
void STInit(ST* ps);
//销毁栈
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);
//获取栈顶元素
STDataType STTop(ST* ps);
//获取栈中有效元素个数
int STSize(ST* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool STEmpty(ST* ps);
void STInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void STPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
void STPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
STDataType STTop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
2つのキュー
2.1 キューの概念と構造
キュー: 一方の端でデータを挿入し、もう一方の端でデータを削除することのみを許可する特殊な線形テーブル。キューは FIFO (先入れ先出し) の原理に従います。
エンキュー: 挿入操作の終わりをキューの終わりと呼びます。
キューの外: 削除操作の終わりはキューの先頭と呼ばれます。
2.2 キューの実装
キューは配列やリンク リストの構造でも実装できますが、配列の構造を使用すると、配列の先頭にあるデータのデキューと出力の効率が相対的に高くなるため、リンク リストの構造を使用することをお勧めします。低い。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
//队列的结构
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Que;
//初始化队列
void QueueInit(Que* pq);
//销毁队列
void QueueDestroy(Que* pq);
//队尾入队列
void QueuePush(Que* pq, QDataType x);
//队头出队列
void QueuePop(Que* pq);
//获取队列头部元素
QDataType QueueFront(Que* pq);
//获取队列队尾元素
QDataType QueueBack(Que* pq);
//检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Que* pq);
//获取队列中有效元素个数
int QueueSize(Que* pq);
void QueueInit(Que* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(Que* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueuePush(Que* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
void QueuePop(Que* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
pq->size--;
}
QDataType QueueFront(Que* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Que* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
bool QueueEmpty(Que* pq)
{
assert(pq);
return pq->head == NULL;
}
int QueueSize(Que* pq)
{
assert(pq);
return pq->size;
}
さらに、実際には循環キューと呼ばれるキューが使用されることがあるということを理解してみましょう。たとえば、オペレーティング システムのコースでプロデューサー消費モデルを説明する場合、循環キューが使用されます。循環キューは、配列または循環リンク リストを使用して実装できます。
記事の終わり