链表还会用吗?用链表实现栈(附算法源码)

链表是一种灵活的数据结构,适合用于需要频繁插入和删除操作的场景,但在需要快速随机访问的情况下,数组或其它数据结构更为合适。

特点

  1. 动态大小

链表可以根据需要动态增长或缩小,不需要事先定义大小。

  1. 非连续存储

链表中的节点在内存中不必连续存储,每个节点通过指针连接。

  1. 插入和删除效率高

在链表中插入或删除节点的时间复杂度为 O(1),只需调整指针即可,而在数组中可能需要移动大量元素,时间复杂度为 O(n)。

  1. 访问效率低

链表的随机访问效率较低,要访问某个节点需要从头遍历,时间复杂度为 O(n)。

适用场景

  1. 实现队列和栈

链表可以方便地实现队列(FIFO)和栈(LIFO)等数据结构,因为它们需要频繁的插入和删除操作。

  1. 动态数据存储

当数据量不确定且需要频繁变化时,链表是一种合适的选择,例如实现动态数组的替代品。

  1. 图和树的实现

链表可用于表示图的邻接表和树的节点结构,方便存储和遍历。

  1. 内存管理

在需要频繁分配和释放内存的应用中,链表可以有效管理内存,避免内存碎片。

使用示例

通过链表的结点来表示栈中的元素。入栈push操作将新元素添加到链表的头部,出栈pop操作则移除链表的头部元素。实现了一个后进先出(LIFO)的栈结构。

#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 定义栈结构
typedef struct Stack {
    Node *top;
} Stack;

// 初始化栈
void initStack(Stack *stack) {
    stack->top = NULL;
}

// 检查栈是否为空
int isEmpty(Stack *stack) {
    return stack->top == NULL;
}

// 入栈操作
void push(Stack *stack, int value) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = stack->top;
    stack->top = newNode;
}

// 出栈操作
int pop(Stack *stack) {
    if (isEmpty(stack)) {
        printf("Stack is empty.\n");
        return -1;
    }
    Node *temp = stack->top;
    int value = temp->data;
    stack->top = stack->top->next;
    free(temp);
    return value;
}

// 释放栈内存
void freeStack(Stack *stack) {
    while (!isEmpty(stack)) {
        pop(stack);
    }
}

int main() {
    Stack stack;
    initStack(&stack);
    
    push(&stack, 10);
    push(&stack, 20);
    push(&stack, 30);

    printf("Popped: %d\n", pop(&stack));
    printf("Popped: %d\n", pop(&stack));
    printf("Popped: %d\n", pop(&stack));
    freeStack(&stack);

    return 0;
}
posted @ 2024-11-23 07:29  Newton爱编程  阅读(22)  评论(0编辑  收藏  举报