栈(LIFO,一端操作)与队列(FIFO,两端操作)都是受限线性表。
栈顶是唯一的活动端。两种实现:
// 顺序栈:数组 + 栈顶下标
typedef struct { int data[1000]; int top; } Stack;
void push(Stack *s, int v) { if (s->top < 1000) s->data[s->top++] = v; }
int pop(Stack *s) { return s->top > 0 ? s->data[--s->top] : -1; }
// 链式栈:复用链表头插,天然 O(1)
typedef struct Node { int val; struct Node *next; } Node;
Node *push(Node *top, int v) {
Node *n = malloc(sizeof(*n));
if (!n) return top;
n->val = v; n->next = top; return n;
}
Node *pop(Node *top) {
if (!top) return NULL;
Node *t = top; top = top->next; free(t); return top;
}
队尾进、队头出。顺序实现若头删后数组前移是 O(n),用循环队列把下标绕回来,头尾操作都 O(1)。
#define CAP 1000
typedef struct { int data[CAP]; int front, rear; } Queue;
// front 指向队头元素,rear 指向队尾下一空位;(rear+1)%CAP == front 视为满,牺牲一格
void enq(Queue *q, int v) {
if ((q->rear + 1) % CAP == q->front) return; // 满
q->data[q->rear] = v; q->rear = (q->rear + 1) % CAP;
}
int deq(Queue *q) {
if (q->front == q->rear) return -1; // 空
int v = q->data[q->front]; q->front = (q->front + 1) % CAP; return v;
}
两端都能进能出。顺序实现同上,链式用双向链表。它兼有栈和队列的能力,是滑动窗口最值问题的常客。
括号匹配:遇左括号入栈,遇右括号弹栈比对。
int match(char *s) {
char st[1000]; int top = 0;
for (int i = 0; s[i]; i++) {
char c = s[i];
if (c == '(' || c == '[' || c == '{') st[top++] = c;
else {
if (top == 0) return 0;
char o = st[--top];
if ((c == ')' && o != '(') || (c == ']' && o != '[') || (c == '}' && o != '{'))
return 0;
}
}
return top == 0;
}
逆波兰(后缀)表达式:中缀 3 + 4 * 2 转后缀 3 4 2 * +,数字入栈、运算符弹两个算完压回,天然无括号、无优先级问题。
对比:栈「同一端进出」回放最近,用于 DFS/函数调用/撤销;队列「一端进一端出」回放最早,用于 BFS/缓冲/消息队列。
对比:顺序需预设容量(或扩容)但无指针开销;链式按需分配无上限,但每节点多一个指针。