手把手教你使用C語言實現堆疊資料結構演算法-兩種方式(連結串列+陣列)

无境之路發表於2024-08-31

堆疊

定義

棧(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;
}

典型應用

  • 瀏覽器的後退與前進,軟體中的撤銷和反撤銷
  • 程式記憶體管理
  • 深度優先演算法,回溯演算法
  • 字尾表示式取值

相關文章