栈(Stack)
栈的定义
- 栈是 后进先出(LIFO) 的数据结构
- 栈操作核心:Push、Pop、Top(取栈顶)、判空
顺序栈(顺序存储)
#define MAXSIZE 100
typedef struct {
int data[MAXSIZE];
int top;
} SqStack;
void InitStack(SqStack &s) {
s.top = -1;
}
bool IsEmpty(SqStack &s) {
return s.top == -1;
}
bool Push(SqStack &s, int x) {
if (s.top == MAXSIZE - 1) return false;
s.data[++s.top] = x;
return true;
}
bool Pop(SqStack &s, int &x) {
if (IsEmpty(s)) return false;
x = s.data[s.top--];
return true;
}
bool GetTop(SqStack &s, int &x) {
if (IsEmpty(s)) return false;
x = s.data[s.top];
return true;
}
链式栈(链栈)
typedef struct StackNode {
int data;
struct StackNode *next;
} StackNode;
typedef struct {
StackNode *top;
} LinkStack;
void InitStack(LinkStack &s) {
s.top = NULL;
}
bool IsEmpty(LinkStack &s) {
return s.top == NULL;
}
bool Push(LinkStack &s, int x) {
StackNode *p = (StackNode *)malloc(sizeof(StackNode));
if (!p) return false;
p->data = x;
p->next = s.top;
s.top = p;
return true;
}
bool Pop(LinkStack &s, int &x) {
if (IsEmpty(s)) return false;
StackNode *p = s.top;
x = p->data;
s.top = p->next;
free(p);
return true;
}
顺序栈 vs 链式栈
| 特性 | 顺序栈(数组实现) | 链式栈(链表实现) |
|---|
| 存储结构 | 数组 | 链表节点 |
| 栈顶操作 | 用 top 下标操作数组 | 用 top 指针操作链表头 |
| 空间容量 | 固定,需要事先定义 MAXSIZE | 动态分配,不受数组长度限制 |
| 判空 | top == -1 | top == NULL |
| 判满 | top == MAXSIZE - 1 | 不需要判断(除非内存耗尽) |
| 入栈操作 | top++,数组赋值 | 头插法,动态分配节点 |
| 出栈操作 | top--,返回数组元素 | 删除栈顶结点,释放内存 |
| 时间复杂度 | O(1) | O(1) |
| 空间利用 | 可能浪费数组空间 | 不会浪费空间,但每个节点有指针开销 |
| 优点 | 内存连续,访问快 | 动态扩展,容量灵活 |
| 缺点 | 容量固定,可能溢出 | 节点额外指针开销,操作稍慢 |
队列(Queue)
队列的定义
- 队列是 先进先出(FIFO) 的数据结构
- 核心操作:入队(EnQueue)、出队(DeQueue)、判空、判满
顺序队列
#define MAXSIZE 100
typedef struct {
int data[MAXSIZE];
int front;
int rear;
} SqQueue;
void InitQueue(SqQueue &q) { q.front = q.rear = 0; }
bool IsEmpty(SqQueue &q) { return q.front == q.rear; }
bool EnQueue(SqQueue &q, int x) {
if (q.rear == MAXSIZE) return false;
q.data[q.rear++] = x;
return true;
}
bool DeQueue(SqQueue &q, int &x) {
if (IsEmpty(q)) return false;
x = q.data[q.front++];
return true;
}
链式队列
struct QNode {
int data;
QNode *next;
};
struct LinkQueue {
QNode *front;
QNode *rear;
};
void InitQueue(LinkQueue &q) { q.front = q.rear = NULL; }
bool IsEmpty(LinkQueue &q) { return q.front == NULL; }
bool EnQueue(LinkQueue &q, int x) {
QNode *p = (QNode *)malloc(sizeof(QNode));
p->data = x;
p->next = NULL;
if (IsEmpty(q)) q.front = q.rear = p;
else { q.rear->next = p; q.rear = p; }
return true;
}
bool DeQueue(LinkQueue &q, int &x) {
if (IsEmpty(q)) return false;
QNode *p = q.front;
x = p->data;
q.front = q.front->next;
if (q.front == NULL) q.rear = NULL;
free(p);
return true;
}
顺序循环队列
#define MAXSIZE 5
typedef struct {
int data[MAXSIZE];
int front;
int rear;
} CirQueue;
void InitQueue(CirQueue &q) {
q.front = q.rear = 0;
}
bool IsEmpty(CirQueue &q) {
return q.front == q.rear;
}
bool EnQueue(CirQueue &q, int x) {
if ((q.rear + 1) % MAXSIZE == q.front) return false;
q.data[q.rear] = x;
q.rear = (q.rear + 1) % MAXSIZE;
return true;
}
bool DeQueue(CirQueue &q, int &x) {
if (IsEmpty(q)) return false;
x = q.data[q.front];
q.front = (q.front + 1) % MAXSIZE;
return true;
}
链式循环队列
struct QNode {
int data;
QNode* next;
};
struct LinkCirQueue {
QNode* front;
QNode* rear;
};
void InitQueue(LinkCirQueue &q) {
q.front = q.rear = NULL;
}
bool IsEmpty(LinkCirQueue &q) {
return q.front == NULL;
}
bool EnQueue(LinkCirQueue &q, int x) {
QNode* node = new QNode;
node->data = x;
if (IsEmpty(q)) {
node->next = node;
q.front = q.rear = node;
} else {
node->next = q.front;
q.rear->next = node;
q.rear = node;
}
return true;
}
bool DeQueue(LinkCirQueue &q, int &x) {
if (IsEmpty(q)) return false;
x = q.front->data;
if (q.front == q.rear) {
free(q.front);
q.front = q.rear = NULL;
} else {
QNode* temp = q.front;
q.front = q.front->next;
q.rear->next = q.front;
free(temp);
}
return true;
}
顺序 vs 链式循环队列
| 特性 | 顺序循环队列 | 链式循环队列 |
|---|
| 存储结构 | 数组 | 链表 |
| 容量限制 | 固定容量 | 动态容量 |
| 判空方法 | front == rear | front == NULL |
| 判满方法 | (rear + 1) % MAXSIZE == front(牺牲一个空间) 或 count == MAXSIZE(全空间用) | 不用判满,动态分配 |
| 优点 | 内存连续、访问快 | 动态、扩展性好 |
| 缺点 | 容量固定,满了需要扩容 | 链表占用额外指针空间,操作稍慢 |