ITPub博客

首页 > 大数据 > 数据分析 > 栈与队列基础:核心操作实现与算法应用解析

栈与队列基础:核心操作实现与算法应用解析

投稿 数据分析 作者:bhluo 时间:2025-12-10 14:31:55 0 删除 编辑

## 栈与队列基础:核心操作实现与算法应用解析


栈和队列作为两种基础而重要的线性数据结构,在计算机科学中扮演着关键角色。栈采用后进先出的访问模式,而队列遵循先进先出的处理原则,这两种不同的数据组织方式分别适用于特定的算法场景。


### 栈的基本定义与实现


栈是一种只能在一端进行插入和删除操作的线性表,该端称为栈顶。栈的核心特性是后进先出,最后入栈的元素最 先出栈。


**数组实现栈**


```c

#define MAX_SIZE 100


typedef struct {

    int data[MAX_SIZE];

    int top;  // 栈顶指针

} ArrayStack;


// 初始化栈

void initStack(ArrayStack *stack) {

    stack->top = -1;  // 空栈时top为-1

}


// 检查栈是否为空

int isEmpty(ArrayStack *stack) {

    return stack->top == -1;

}


// 检查栈是否已满

int isFull(ArrayStack *stack) {

    return stack->top == MAX_SIZE - 1;

}


// 入栈操作

int push(ArrayStack *stack, int value) {

    if (isFull(stack)) {

        printf("栈已满,无法入栈\n");

        return 0;

    }

    stack->data[++stack->top] = value;

    return 1;

}


// 出栈操作

int pop(ArrayStack *stack, int *value) {

    if (isEmpty(stack)) {

        printf("栈为空,无法出栈\n");

        return 0;

    }

    *value = stack->data[stack->top--];

    return 1;

}


// 获取栈顶元素

int peek(ArrayStack *stack, int *value) {

    if (isEmpty(stack)) {

        printf("栈为空\n");

        return 0;

    }

    *value = stack->data[stack->top];

    return 1;

}

```


**链表实现栈**


```c

typedef struct StackNode {

    int data;

    struct StackNode *next;

} StackNode;


typedef struct {

    StackNode *top;  // 栈顶指针

    int size;        // 栈中元素个数

} LinkedStack;


// 初始化栈

void initLinkedStack(LinkedStack *stack) {

    stack->top = NULL;

    stack->size = 0;

}


// 入栈操作

void linkedPush(LinkedStack *stack, int value) {

    StackNode *newNode = (StackNode*)malloc(sizeof(StackNode));

    if (!newNode) {

        printf("内存分配失败\n");

        return;

    }

    

    newNode->data = value;

    newNode->next = stack->top;  // 新节点指向原栈顶

    stack->top = newNode;        // 更新栈顶指针

    stack->size++;

}


// 出栈操作

int linkedPop(LinkedStack *stack, int *value) {

    if (stack->top == NULL) {

        printf("栈为空\n");

        return 0;

    }

    

    StackNode *temp = stack->top;

    *value = temp->data;

    stack->top = temp->next;     // 更新栈顶指针

    free(temp);

    stack->size--;

    return 1;

}

```


### 队列的基本定义与实现


队列是一种在一端插入、另一端删除的线性表,插入端称为队尾,删除端称为队头。队列遵循先进先出的原则。


**数组实现循环队列**


```c

#define QUEUE_SIZE 100


typedef struct {

    int data[QUEUE_SIZE];

    int front;  // 队头指针

    int rear;   // 队尾指针

    int count;  // 队列中元素个数

} CircularQueue;


// 初始化队列

void initQueue(CircularQueue *queue) {

    queue->front = 0;

    queue->rear = 0;

    queue->count = 0;

}


// 检查队列是否为空

int isQueueEmpty(CircularQueue *queue) {

    return queue->count == 0;

}


// 检查队列是否已满

int isQueueFull(CircularQueue *queue) {

    return queue->count == QUEUE_SIZE;

}


// 入队操作

int enqueue(CircularQueue *queue, int value) {

    if (isQueueFull(queue)) {

        printf("队列已满\n");

        return 0;

    }

    

    queue->data[queue->rear] = value;

    queue->rear = (queue->rear + 1) % QUEUE_SIZE;  // 循环移动

    queue->count++;

    return 1;

}


// 出队操作

int dequeue(CircularQueue *queue, int *value) {

    if (isQueueEmpty(queue)) {

        printf("队列为空\n");

        return 0;

    }

    

    *value = queue->data[queue->front];

    queue->front = (queue->front + 1) % QUEUE_SIZE;  // 循环移动

    queue->count--;

    return 1;

}


// 获取队头元素

int getFront(CircularQueue *queue, int *value) {

    if (isQueueEmpty(queue)) {

        printf("队列为空\n");

        return 0;

    }

    

    *value = queue->data[queue->front];

    return 1;

}

```


**链表实现队列**


```c

typedef struct QueueNode {

    int data;

    struct QueueNode *next;

} QueueNode;

<"7h.adfw.cn"><"2e.adfw.cn"><"9l.adfw.cn">

typedef struct {

    QueueNode *front;  // 队头指针

    QueueNode *rear;   // 队尾指针

    int size;          // 队列大小

} LinkedQueue;


// 初始化队列

void initLinkedQueue(LinkedQueue *queue) {

    queue->front = NULL;

    queue->rear = NULL;

    queue->size = 0;

}


// 入队操作

void linkedEnqueue(LinkedQueue *queue, int value) {

    QueueNode *newNode = (QueueNode*)malloc(sizeof(QueueNode));

    if (!newNode) {

        printf("内存分配失败\n");

        return;

    }

    

    newNode->data = value;

    newNode->next = NULL;

    

    if (queue->rear == NULL) {  // 空队列

        queue->front = queue->rear = newNode;

    } else {

        queue->rear->next = newNode;

        queue->rear = newNode;

    }

    queue->size++;

}


// 出队操作

int linkedDequeue(LinkedQueue *queue, int *value) {

    if (queue->front == NULL) {

        printf("队列为空\n");

        return 0;

    }

    

    QueueNode *temp = queue->front;

    *value = temp->data;

    queue->front = queue->front->next;

    

    // 如果出队后队列为空,更新rear指针

    if (queue->front == NULL) {

        queue->rear = NULL;

    }

    

    free(temp);

    queue->size--;

    return 1;

}

```


### 栈与队列的核心操作复杂度分析


**时间复杂度比较**


```c

// 栈操作的时间复杂度

void analyzeStackComplexity() {

    // 数组实现的栈:

    // push: O(1) 平均,当需要扩容时为O(n)

    // pop:  O(1)

    // peek: O(1)

    

    // 链表实现的栈:

    // push: O(1)

    // pop:  O(1)

    // peek: O(1)

}


// 队列操作的时间复杂度

void analyzeQueueComplexity() {

    // 循环队列:

    // enqueue: O(1)

    // dequeue: O(1)

    // getFront: O(1)

    

    // 链表队列:

    // enqueue: O(1)

    // dequeue: O(1)

    // getFront: O(1)

}

```


**空间复杂度分析**


```c

// 空间复杂度对比

void analyzeSpaceComplexity() {

    // 数组实现:

    // 栈/队列:O(n),n为预先分配的数组大小

    // 优点:连续内存,缓存友好

    // 缺点:大小固定,可能浪费空间或需要扩容

    

    // 链表实现:

    // 栈/队列:O(n),n为实际元素个数

    // 优点:动态扩展,无空间浪费

    // 缺点:额外指针开销,内存碎片

}

```


### 栈的典型应用场景


**括号匹配验证**


```c

int isValidParentheses(char *s) {

    char stack[10000];

    int top = -1;

    

    for (int i = 0; s[i] != '\0'; i++) {

        char ch = s[i];

        

        if (ch == '(' || ch == '[' || ch == '{') {

            // 左括号入栈

            stack[++top] = ch;

        } else {

            // 右括号检查匹配

            if (top == -1) return 0;  // 栈为空

            

            char topChar = stack[top];

            if ((ch == ')' && topChar == '(') ||

                (ch == ']' && topChar == '[') ||

                (ch == '}' && topChar == '{')) {

                top--;  // 匹配成功,出栈

            } else {

                return 0;  // 不匹配

            }

        }

    }

    

    return top == -1;  // 栈为空说明全部匹配

}

```


**表达式求值**


```c

// 中缀表达式转后缀表达式

void infixToPostfix(char *infix, char *postfix) {

    char stack[1000];

    int top = -1;

    int j = 0;

    

    for (int i = 0; infix[i] != '\0'; i++) {

        char ch = infix[i];

        

        if (isdigit(ch)) {

            // 操作数直接输出

            postfix[j++] = ch;

        } else if (ch == '(') {

            // 左括号入栈

            stack[++top] = ch;

        } else if (ch == ')') {

            // 右括号:弹出直到遇到左括号

            while (top != -1 && stack[top] != '(') {

                postfix[j++] = stack[top--];

            }

            top--;  // 弹出左括号

        } else {

            // 运算符:根据优先级处理

            while (top != -1 && precedence(stack[top]) >= precedence(ch)) {

                postfix[j++] = stack[top--];

            }

            stack[++top] = ch;

        }

    }

    

    // 弹出栈中剩余运算符

    while (top != -1) {

        postfix[j++] = stack[top--];

    }

    postfix[j] = '\0';

}


int precedence(char op) {

    switch (op) {

        case '+':

        case '-': return 1;

        case '*':

        case '/': return 2;

        default: return 0;

    }

}

```


### 队列的典型应用场景


**广度优先搜索中的队列应用**


```c

// 使用队列实现图的BFS

void bfs(int graph[][MAX_N], int start, int vertices) {

    int visited[MAX_N] = {0};

    CircularQueue queue;

    initQueue(&queue);

    

    visited[start] = 1;

    enqueue(&queue, start);

    

    printf("BFS遍历顺序: ");

    

    while (!isQueueEmpty(&queue)) {

        int current;

        dequeue(&queue, &current);

        printf("%d ", current);

        

        // 遍历相邻节点

        for (int i = 0; i < vertices; i++) {

            if (graph[current][i] == 1 && !visited[i]) {

                visited[i] = 1;

                enqueue(&queue, i);

            }<"4t.adfw.cn"><"0u.adfw.cn"><"5e.adfw.cn">

        }

    }

    printf("\n");

}

```


**任务调度系统**


```c

typedef struct {

    int taskId;

    int priority;

    char description[100];

} Task;


typedef struct {

    Task tasks[MAX_TASKS];

    int front;

    int rear;

    int size;

} TaskQueue;


// 任务调度器

void taskScheduler(TaskQueue *queue) {

    while (queue->size > 0) {

        Task currentTask;

        if (dequeueTask(queue, &currentTask)) {

            printf("执行任务 %d: %s (优先级: %d)\n", 

                   currentTask.taskId, 

                   currentTask.description, 

                   currentTask.priority);

            

            // 模拟任务执行

            // ...

        }

    }

    printf("所有任务执行完成\n");

}

```


### 双端队列的特殊应用


双端队列结合了栈和队列的特性,可以在两端进行插入和删除操作。


```c

#define DEQUE_SIZE 100


typedef struct {

    int data[DEQUE_SIZE];

    int front;

    int rear;

    int size;

} Deque;


// 前端插入

void insertFront(Deque *deque, int value) {

    if (deque->size == DEQUE_SIZE) {

        printf("双端队列已满\n");

        return;

    }

    

    if (deque->size == 0) {

        deque->front = deque->rear = 0;

    } else {

        deque->front = (deque->front - 1 + DEQUE_SIZE) % DEQUE_SIZE;

    }

    

    deque->data[deque->front] = value;

    deque->size++;

}


// 后端插入

void insertRear(Deque *deque, int value) {

    if (deque->size == DEQUE_SIZE) {

        printf("双端队列已满\n");

        return;

    }

    

    if (deque->size == 0) {

        deque->front = deque->rear = 0;

    } else {

        deque->rear = (deque->rear + 1) % DEQUE_SIZE;

    }

    

    deque->data[deque->rear] = value;

    deque->size++;

}


// 前端删除

int deleteFront(Deque *deque, int *value) {

    if (deque->size == 0) {

        printf("双端队列为空\n");

        return 0;

    }

    

    *value = deque->data[deque->front];

    deque->front = (deque->front + 1) % DEQUE_SIZE;

    deque->size--;

    

    return 1;

}

```


### 栈与队列的选择策略


**何时选择栈**

1. 需要后进先出访问顺序的场景

2. 递归函数的系统栈实现

3. 深度优先搜索中的路径记录

4. 语法解析和表达式求值

5. 撤销操作功能实现


**何时选择队列**

1. 需要先进先出处理顺序的场景

2. 广度优先搜索中的节点管理

3. 任务调度和消息传递系统

4. 缓冲区管理和数据流处理

5. 打印队列和请求处理


**性能对比表**

```

特性       数组栈    链表栈    循环队列    链表队列

插入速度    O(1)      O(1)      O(1)       O(1)

删除速度    O(1)      O(1)      O(1)       O(1)

空间效率    固定      动态      固定       动态

内存局部性  好        差        好         差

扩容成本    高        低        高         低

```


### 实际编程中的最佳实践


**栈的实现建议**

```c

// 使用动态数组实现可扩容的栈

typedef struct {

    int *data;

    int top;

    int capacity;

} DynamicStack;


void resizeStack(DynamicStack *stack) {

    stack->capacity *= 2;

    stack->data = realloc(stack->data, 

                         stack->capacity * sizeof(int));

}

```


**队列的实现建议**

```c

// 使用链表实现无界队列

typedef struct {

    Node *front;

    Node *rear;

    pthread_mutex_t lock;  // 线程安全

} ThreadSafeQueue;

```


### 总结与扩展


栈和队列作为基础数据结构,其重要性不仅体现在简单的存储功能上,更在于它们为解决复杂问题提供了基本的模式框架。理解这两种数据结构的核心特性、实现方式及应用场景,是算法学习的重要基础。


从基础实现到高级应用,栈和队列展现了计算机科学中抽象的力量。栈的后进先出特性自然对应函数调用、回溯算法等场景,而队列的先进先出特性则完美匹配任务调度、广度优先搜索等需求。掌握这两种数据结构,能够为解决更复杂的算法问题奠定坚实基础。


在实际开发中,应根据具体需求选择合适的数据结构实现。对于固定大小的场景,数组实现具有更好的性能;对于需要动态扩展的情况,链表实现提供更大的灵活性。理解这些权衡,能够帮助开发者做出更明智的技术选择。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3104876/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    934229