算法-栈与队列
栈
「栈 stack」是一种遵循先入后出逻辑的线性数据结构。
栈的常用操作
出栈,入栈,访问栈顶元素
链表实现
/* 基于链表实现的栈 */
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;
}
数组实现
/* 基于数组实现的栈 */
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;
}
栈的典型应用
浏览器中的后退与前进、软件中的撤销与反撤销。每当我们打开新的网页,浏览器就会对上一个网页执行入栈,这样我们就可以通过后退操作回到上一个网页。后退操作实际上是在执行出栈。如果要同时支持后退和前进,那么需要两个栈来配合实现。
程序内存管理。每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会不断执行出栈操作。
队列
「队列 queue」是一种遵循先入先出规则的线性数据结构。
队列的常见操作
出队,入队,访问对首元素
/* 基于链表实现的队列 */
typedef struct {
ListNode *front, *rear;
int queSize;
} LinkedListQueue;
/* 构造函数 */
LinkedListQueue *newLinkedListQueue() {
LinkedListQueue *queue = (LinkedListQueue *)malloc(sizeof(LinkedListQueue));
queue->front = NULL;
queue->rear = NULL;
queue->queSize = 0;
return queue;
}
/* 析构函数 */
void delLinkedListQueue(LinkedListQueue *queue) {
// 释放所有节点
while (queue->front != NULL) {
ListNode *tmp = queue->front;
queue->front = queue->front->next;
free(tmp);
}
// 释放 queue 结构体
free(queue);
}
/* 获取队列的长度 */
int size(LinkedListQueue *queue) {
return queue->queSize;
}
/* 判断队列是否为空 */
bool empty(LinkedListQueue *queue) {
return (size(queue) == 0);
}
/* 入队 */
void push(LinkedListQueue *queue, int num) {
// 尾节点处添加 node
ListNode *node = newListNode(num);
// 如果队列为空,则令头、尾节点都指向该节点
if (queue->front == NULL) {
queue->front = node;
queue->rear = node;
}
// 如果队列不为空,则将该节点添加到尾节点后
else {
queue->rear->next = node;
queue->rear = node;
}
queue->queSize++;
}
/* 访问队首元素 */
int peek(LinkedListQueue *queue) {
assert(size(queue) && queue->front);
return queue->front->val;
}
/* 出队 */
int pop(LinkedListQueue *queue) {
int num = peek(queue);
ListNode *tmp = queue->front;
queue->front = queue->front->next;
free(tmp);
queue->queSize--;
return num;
}
/* 打印队列 */
void printLinkedListQueue(LinkedListQueue *queue) {
int *arr = malloc(sizeof(int) * queue->queSize);
// 拷贝链表中的数据到数组
int i;
ListNode *node;
for (i = 0, node = queue->front; i < queue->queSize; i++) {
arr[i] = node->val;
node = node->next;
}
printArray(arr, queue->queSize);
free(arr);
}
评论区