堆疊
定義
棧(stack) 是一種遵循先入後出邏輯的線性資料結構,常見操作入棧,出棧,訪問棧
圖片來源:https://www.hello-algo.com/
棧的實現
棧遵循先入後出的原則,因此我們只能在棧頂新增或刪除元素。然而,陣列和連結串列都可以在任意位置新增和刪除元素,因此棧可以視為一種受限制的陣列或連結串列。換句話說,我們可以“遮蔽”陣列或連結串列的部分無關操作,使其對外表現的邏輯符合棧的特性。
基於連結串列的實現
使用連結串列實現棧時,我們只需將連結串列的頭節點視為棧頂,尾節點視為棧底
入棧操作,只需將元素插入連結串列頭部(這種節點插入方式被稱為“頭插法”),出棧操作,只需將頭結點從連結串列中刪除即可。
/* 基於連結串列實現的棧 */
typedef struct
{
ListNode *top; // 將頭節點作為棧頂
int size; // 棧的長度
} LinkedListStack;
/* 建構函式 */
LinkedListStack *newLinkedListStack()
{
LinkedListStack *s = malloc(sizeof(LinkedListStack));
s->top = NULL;
s->size = 0;
return s;
}
/* 解構函式 */
void delLinkedListStack(LinkedListStack *s)
{
while (s->top)
{
ListNode *n = s->top->next;
free(s->top);
s->top = n;
}
free(s);
}
/* 獲取棧的長度 */
int size(LinkedListStack *s)
{
return s->size;
}
/* 判斷棧是否為空 */
bool isEmpty(LinkedListStack *s)
{
return size(s) == 0;
}
/* 入棧 */
void push(LinkedListStack *s, int num)
{
ListNode *node = (ListNode *)malloc(sizeof(ListNode));
node->next = s->top; // 更新新加節點指標域
node->val = num; // 更新新加節點資料域
s->top = node; // 更新棧頂
s->size++; // 更新棧大小
}
/* 訪問棧頂元素 */
int peek(LinkedListStack *s)
{
if (s->size == 0)
{
printf("棧為空\n");
return INT_MAX;
}
return s->top->val;
}
/* 出棧 */
int pop(LinkedListStack *s)
{
int val = peek(s);
ListNode *tmp = s->top;
s->top = s->top->next;
// 釋放記憶體
free(tmp);
s->size--;
return val;
}
基於陣列的實現
使用陣列實現棧時,可以將陣列的尾部作為棧頂,入棧,出棧分別在尾部新增與刪除元素,時間複雜度為O(1);
由於入棧元素可能會源源不斷的增加,使用動態陣列操作可避免後續增容操作
/* 基於陣列實現的棧 */
typedef struct
{
int *data;
int size;
} ArrayStack;
/* 建構函式 */
ArrayStack *newArrayStack()
{
ArrayStack *stack = malloc(sizeof(ArrayStack));
// 初始化一個大容量,避免擴容
stack->data = malloc(sizeof(int) * MAX_SIZE);
stack->size = 0;
return stack;
}
/* 解構函式 */
void delArrayStack(ArrayStack *stack)
{
free(stack->data);
free(stack);
}
/* 獲取棧的長度 */
int size(ArrayStack *stack)
{
return stack->size;
}
/* 判斷棧是否為空 */
bool isEmpty(ArrayStack *stack)
{
return stack->size == 0;
}
/* 入棧 */
void push(ArrayStack *stack, int num)
{
if (stack->size == MAX_SIZE)
{
printf("棧已滿\n");
return;
}
stack->data[stack->size] = num;
stack->size++;
}
/* 訪問棧頂元素 */
int peek(ArrayStack *stack)
{
if (stack->size == 0)
{
printf("棧為空\n");
return INT_MAX;
}
return stack->data[stack->size - 1];
}
/* 出棧 */
int pop(ArrayStack *stack)
{
int val = peek(stack);
stack->size--;
return val;
}
/* 測試程式碼 */
int main()
{
ArrayStack *stack = newArrayStack();
push(stack, 1);
push(stack, 2);
push(stack, 3);
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
delArrayStack(stack);
return 0;
}
典型應用
- 瀏覽器的後退與前進,軟體中的撤銷和反撤銷
- 程式記憶體管理
- 深度優先演算法,回溯演算法
- 字尾表示式取值