栈的理解:
物理意义上的栈是在内存中是给函数开辟空间的一块区域。举个例子,当我使用自定义函数的时候,内存中的栈区会开辟一块空间给这个函数,然后当退出这块区域时,会销毁这块区域。
而承接这块开辟区域的物理方式之一就是数组,所以今天我将带大家通过数组的角度来理解栈
栈的基本操作
栈是一种后进先出(LIFO)的数据结构,主要操作包括:
- 初始化栈:创建一个空栈,通常需要分配内存空间并设置栈顶指针。
-
#include <stdio.h> #include <stdlib.h> //先确定我要存放的有效元素的最大值 #define MAX_SIZE 100 //栈的结构体定义 typedef struct { int data[MAX_SIZE];//存放元素的空间,也就是栈 int top;//指向首个插入元素的位置,也就是栈顶 } Stack; //栈的初始化,表示栈为空 void initStack(Stack *s) { s->top = -1; } - 入栈(Push):将元素添加到栈顶,栈顶指针向上移动。
-
// 判断栈是否已满 int isFull(Stack *s) { return s->top == MAX_SIZE - 1; // 栈顶达到最大索引则为满 } // 入栈操作:向栈顶添加元素 int push(Stack *s, int value) { if (isFull(s)) { printf("栈已满,无法入栈\n"); return 0; // 入栈失败 } s->top++; // 栈顶指针上移 s->data[s->top] = value; // 将元素存入栈顶位置 return 1; // 入栈成功 } - 出栈(Pop):移除栈顶元素并返回其值,栈顶指针向下移动。
-
// 出栈操作:从栈顶移除元素,并返回该元素 int pop(Stack *s, int *value) { if (isEmpty(s)) { printf("栈为空,无法出栈\n"); return 0; // 出栈失败 } *value = s->data[s->top]; // 获取栈顶元素 s->top--; // 栈顶指针下移 return 1; // 出栈成功 } - 获取栈顶元素(Peek/Top):返回栈顶元素的值,但不移除它。
-
// 获取栈顶元素,但不移除 int getTop(Stack *s, int *value) { if (isEmpty(s)) { printf("栈为空,无栈顶元素\n"); return 0; // 获取失败 } *value = s->data[s->top]; // 获取栈顶元素 return 1; // 获取成功 } - 判断栈是否为空(IsEmpty):检查栈中是否有元素。
-
// 判断栈是否为空 int isEmpty(Stack *s) { return s->top == -1; // 栈顶为-1则为空 } - 获取栈的大小(Size):返回栈中元素的数量。
栈学习中的问题:
1、首先带大家理清的是top的初始化,这和入栈这步操作是脱离不了干系的,当我们想插入元素时,我们同时也要让top向后移,方便下一步操作,这时我们就需要根据top后移和插入元素这两步的先后关系来定义top的初始值,因为我们要始终要让top指向栈顶元素的位置,所以在上述代码中,我是先进行top++,因此当插入元素时,我们就应该使top的值为0(因为数组首元素下标为0),所以我们会初始化top为-1。
目录
队列的基本操作
队列是一种先进先出(FIFO)的数据结构,类型有链式队列和顺序队列,接下来我讲的是顺序队列:
- 初始化队列:创建一个空队列,通常需要分配内存空间并设置队首和队尾指针。
-
// 顺序队列结构体 typedef struct { int data[MAX_SIZE]; // 存储队列元素的数组 int front; // 队头指针(指向队头元素) int rear; // 队尾指针(指向队尾元素的下一个位置) } SeqQueue; // 初始化队列(创建空队列) void initQueue(SeqQueue *q) { q->front = 0; // 队头初始化为0 q->rear = 0; // 队尾初始化为0(表示队列为空) } - 入队(Enqueue):将元素添加到队尾,队尾指针向后移动。
-
// 入队操作 int enqueue(SeqQueue *q, int value) { if (isFull(q)) { printf("队列已满,无法入队\n"); return 0; } q->data[q->rear] = value; // 存入元素 q->rear = (q->rear + 1) % MAX_SIZE; // 队尾指针后移(循环队列) return 1; } - 出队(Dequeue):移除队首元素并返回其值,队首指针向后移动。
-
/ 出队操作 int dequeue(SeqQueue *q, int *value) { if (isEmpty(q)) { printf("队列为空,无法出队\n"); return 0; } *value = q->data[q->front]; // 取出队头元素 q->front = (q->front + 1) % MAX_SIZE; // 队头指针后移(循环队列) return 1; } - 获取队首元素(Front):返回队首元素的值,但不移除它。
-
/ 顺序队列获取队首元素(不删除) int getSeqQueueFront(SeqQueue *q, int *value) { if (q->front == q->rear) { // 队列为空 return 0; // 获取失败 } *value = q->data[q->front]; // 仅返回队首元素值,不修改队列 return 1; // 获取成功 } - 判断队列是否为空(IsEmpty):检查队列中是否有元素。
-
// 判断队列是否为空 int isEmpty(SeqQueue *q) { return q->front == q->rear; } - 获取队列的大小(Size):返回队列中元素的数量。
-
// 获取顺序队列大小 int getSeqQueueSize(SeqQueue *q) { // 循环队列公式:(队尾 - 队头 + 最大容量) % 最大容量 return (q->rear - q->front + MAX_SIZE) % MAX_SIZE; }
栈的C语言实现示例
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int top;
} Stack;
void initStack(Stack *s) {
s->top = -1;
}
int isEmpty(Stack *s) {
return s->top == -1;
}
int isFull(Stack *s) {
return s->top == MAX_SIZE - 1;
}
void push(Stack *s, int value) {
if (isFull(s)) {
printf("Stack overflow\n");
return;
}
s->data[++s->top] = value;
}
int pop(Stack *s) {
if (isEmpty(s)) {
printf("Stack underflow\n");
exit(1);
}
return s->data[s->top--];
}
int peek(Stack *s) {
if (isEmpty(s)) {
printf("Stack is empty\n");
exit(1);
}
return s->data[s->top];
}
队列的C语言实现示例
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int front;
int rear;
} Queue;
void initQueue(Queue *q) {
q->front = 0;
q->rear = -1;
}
int isEmpty(Queue *q) {
return q->rear < q->front;
}
int isFull(Queue *q) {
return q->rear == MAX_SIZE - 1;
}
void enqueue(Queue *q, int value) {
if (isFull(q)) {
printf("Queue overflow\n");
return;
}
q->data[++q->rear] = value;
}
int dequeue(Queue *q) {
if (isEmpty(q)) {
printf("Queue underflow\n");
exit(1);
}
return q->data[q->front++];
}
int front(Queue *q) {
if (isEmpty(q)) {
printf("Queue is empty\n");
exit(1);
}
return q->data[q->front];
}
注意事项
- 栈和队列的实现:可以使用数组或链表实现,数组实现简单但大小固定,链表实现灵活但需要更多内存管理。
- 边界条件:操作时需检查栈或队列是否为空或已满,避免溢出或下溢。
- 动态扩展:链表实现可以动态扩展,数组实现通常需要预先分配固定大小。
- 栈的特点:一端操作、后进先出、高效灵活、线性结构

4640

被折叠的 条评论
为什么被折叠?



