Administrator
Administrator
发布于 2024-09-06 / 4 阅读
0
0

第2,3节

接下来我们继续深入学习数据结构中的队列。这些是非常常用的数据结构,它们在许多应用场景中都有重要的作用,如表达式求值、递归、任务调度等。

第2节:栈(Stack)

2.1 栈的基本概念

栈(Stack)是一种**后进先出(LIFO)**的数据结构。栈的操作主要有两个:

  • push:将元素压入栈顶。

  • pop:将栈顶元素弹出。

栈的应用包括:

  • 递归调用的处理

  • 表达式求值和语法解析

  • 深度优先搜索(DFS)

2.2 栈的数组实现

栈的基本结构


#include <stdio.h>

#include <stdlib.h>

#define MAX 100

// 定义栈结构

struct Stack {

    int items[MAX]; // 用数组存储栈元素

    int top; // 栈顶指针

};

// 初始化栈

void initStack(struct Stack* s) {

    s->top = -1; // 初始时栈为空

}

// 检查栈是否满

int isFull(struct Stack* s) {

    return s->top == MAX - 1;

}

// 检查栈是否为空

int isEmpty(struct Stack* s) {

    return s->top == -1;

}

// 压栈操作

void push(struct Stack* s, int value) {

    if (isFull(s)) {

        printf("Stack is full! Cannot push %d\n", value);

        return;

    }

    s->items[++(s->top)] = value;

}

// 弹栈操作

int pop(struct Stack* s) {

    if (isEmpty(s)) {

        printf("Stack is empty! Cannot pop\n");

        return -1;

    }

    return s->items[(s->top)--];

}

// 获取栈顶元素

int peek(struct Stack* s) {

    if (isEmpty(s)) {

        printf("Stack is empty!\n");

        return -1;

    }

    return s->items[s->top];

}

完整示例:使用数组实现栈


int main() {

    struct Stack s;

    initStack(&s);

    push(&s, 10);

    push(&s, 20);

    push(&s, 30);

    printf("Top element: %d\n", peek(&s));

    printf("Pop element: %d\n", pop(&s));

    printf("Pop element: %d\n", pop(&s));

    if (isEmpty(&s)) {

        printf("Stack is empty\n");

    }

    return 0;

}

2.3 栈的链表实现

栈也可以使用链表来实现,这样可以避免固定大小的限制,使栈的大小动态可变。

链表节点的定义


struct Node {

    int data;

    struct Node* next;

};

栈操作


// 初始化链表栈

void initStack(struct Node** top) {

    *top = NULL;

}

// 压栈操作

void push(struct Node** top, int value) {

    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

    if (!newNode) {

        printf("Memory allocation failed\n");

        return;

    }

    newNode->data = value;

    newNode->next = *top;

    *top = newNode;

}

// 弹栈操作

int pop(struct Node** top) {

    if (*top == NULL) {

        printf("Stack is empty! Cannot pop\n");

        return -1;

    }

    struct Node* temp = *top;

    int poppedValue = temp->data;

    *top = temp->next;

    free(temp);

    return poppedValue;

}

// 获取栈顶元素

int peek(struct Node* top) {

    if (top == NULL) {

        printf("Stack is empty!\n");

        return -1;

    }

    return top->data;

}

完整示例:使用链表实现栈


int main() {

    struct Node* stack = NULL;

    initStack(&stack);

    push(&stack, 10);

    push(&stack, 20);

    push(&stack, 30);

    printf("Top element: %d\n", peek(stack));

    printf("Pop element: %d\n", pop(&stack));

    printf("Pop element: %d\n", pop(&stack));

    if (stack == NULL) {

        printf("Stack is empty\n");

    }

    return 0;

}

第3节:队列(Queue)

3.1 队列的基本概念

队列(Queue)是一种**先进先出(FIFO)**的数据结构,广泛应用于任务调度、操作系统的进程管理、广度优先搜索等场景。

队列的操作主要包括:

  • enqueue:将元素加入队列的末尾。

  • dequeue:将元素从队列的开头移出。

3.2 队列的数组实现

队列的基本结构


#include <stdio.h>

#include <stdlib.h>

#define MAX 100

// 定义队列结构

struct Queue {

    int items[MAX]; // 用数组存储队列元素

    int front, rear; // 队列的头指针和尾指针

};

// 初始化队列

void initQueue(struct Queue* q) {

    q->front = -1;

    q->rear = -1;

}

// 检查队列是否为空

int isEmpty(struct Queue* q) {

    return q->front == -1;

}

// 检查队列是否已满

int isFull(struct Queue* q) {

    return q->rear == MAX - 1;

}

// 入队操作

void enqueue(struct Queue* q, int value) {

    if (isFull(q)) {

        printf("Queue is full! Cannot enqueue %d\n", value);

        return;

    }

    if (isEmpty(q)) {

        q->front = 0; // 第一个元素插入时,更新 front

    }

    q->items[++(q->rear)] = value;

}

// 出队操作

int dequeue(struct Queue* q) {

    if (isEmpty(q)) {

        printf("Queue is empty! Cannot dequeue\n");

        return -1;

    }

    int value = q->items[q->front];

    if (q->front == q->rear) {

        q->front = q->rear = -1; // 队列为空时,重置指针

    } else {

        q->front++;

    }

    return value;

}

完整示例:使用数组实现队列


int main() {

    struct Queue q;

    initQueue(&q);

    enqueue(&q, 10);

    enqueue(&q, 20);

    enqueue(&q, 30);

    printf("Dequeue element: %d\n", dequeue(&q));

    printf("Dequeue element: %d\n", dequeue(&q));

    if (isEmpty(&q)) {

        printf("Queue is empty\n");

    }

    return 0;

}

3.3 队列的链表实现

类似于栈,队列也可以用链表来实现。链表实现的队列在需要动态增长的场景中非常适合。

队列节点的定义


struct Node {

    int data;

    struct Node* next;

};

队列操作


struct Queue {

    struct Node front, rear;

};

// 初始化队列

void initQueue(struct Queue* q) {

    q->front = q->rear = NULL;

}

// 入队操作

void enqueue(struct Queue* q, int value) {

    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

    if (!newNode) {

        printf("Memory allocation failed\n");

        return;

    }

    newNode->data = value;

    newNode->next = NULL;

    if (q->rear == NULL) {

        q->front = q->rear = newNode;

        return;

    }

    q->rear->next = newNode;

    q->rear = newNode;

}

// 出队操作

int dequeue(struct Queue* q) {

    if (q->front == NULL) {

        printf("Queue is empty! Cannot dequeue\n");

        return -1;

    }

    struct Node* temp = q->front;

    int dequeuedValue = temp->data;

    q->front = q->front->next;

    if (q->front == NULL) {

        q->rear = NULL;

    }

    free(temp);

    return dequeuedValue;

}

完整示例:使用链表实现队列


int main() {

    struct Queue q;

    initQueue(&q);

    enqueue(&q, 10);

    enqueue(&q, 20);

    enqueue(&q, 30);

    printf("Dequeue element: %d\n", dequeue(&q));

    printf("Dequeue element: %d\n", dequeue(&q));

    if (q.front == NULL) {

        printf("Queue is empty\n");

    }

    return 0;

}

练习题

  1. 最小栈:设计一个支持 push、pop 和 getMin 操作的栈,getMin 应返回栈中的最小值,时间复杂度应为 O(1)。

  2. 中缀表达式求值:使用栈实现中缀表达式的求值。

  3. 环形队列:实现一个环形队列,支持循环利用空间。

  4. 双端队列(Deque):实现一个双端队列,可以从两端插入和删除元素。

  5. 队列的栈实现:使用两个栈实现一个队列,支持 enqueue 和 dequeue 操作。

完成这些练习后,你将对栈和队列的数据结构有深入理解。接下来,我们可以继续学习其他数据结构,如


评论