C语言中以数组首元素为栈顶实现栈的疑问求解
arr[0]的C语言栈 嘿,这个需求其实就是把常规栈的存储逻辑反过来玩——通常我们的栈是往数组下标增大的方向存元素,栈顶随元素增加“向右跑”,但现在要求栈顶固定在arr[0],新元素必须放在这里,旧元素得乖乖往后“让位”。我给你一步步拆解实现思路和代码:
核心逻辑先理清
要满足arr[0]是栈顶(也就是最后入栈的元素永远在这个位置),得记住这几点:
- 入栈时:先把已有的所有元素向后移动一位,给新元素腾位置,再把新元素放到
arr[0] - 出栈时:先取出
arr[0]的值,再把剩下的元素向前移动一位,保证下一个栈顶还是arr[0] - 需要用一个变量记录当前栈里的元素数量,用来判断栈空/栈满,以及移动元素时的边界
1. 定义栈的结构体
首先我们需要一个结构体来封装栈的数组、最大容量和当前元素数量:
#define MAX_STACK_SIZE 100 // 可以根据需求调整栈的最大容量 typedef struct { int arr[MAX_STACK_SIZE]; // 存储栈元素的数组 int size; // 当前栈的元素个数,初始为0 } Stack;
这里用size代替常规栈的top下标,因为我们的栈顶位置是固定的,只需要知道有多少元素在栈里就行。
2. 初始化栈
初始化超级简单,把size设为0就代表栈是空的:
void initStack(Stack *stack) { stack->size = 0; }
3. 栈空/栈满判断
这两个辅助函数是栈操作的基础:
- 栈空:
size == 0,此时arr[0]没有有效数据 - 栈满:
size == MAX_STACK_SIZE,数组已经放满,没法再往后挪元素了
// 判断栈是否为空,空返回1,非空返回0 int isEmpty(Stack *stack) { return stack->size == 0; } // 判断栈是否已满,满返回1,未满返回0 int isFull(Stack *stack) { return stack->size == MAX_STACK_SIZE; }
4. 入栈操作(Push)
入栈的关键是从后往前移动已有元素,避免覆盖数据,然后把新元素放到arr[0]:
// 入栈:成功返回1,栈满返回0 int push(Stack *stack, int value) { if (isFull(stack)) { printf("栈已满,无法入栈!\n"); return 0; } // 从最后一个元素开始,依次向后挪一位(防止前面的元素被覆盖) for (int i = stack->size; i > 0; i--) { stack->arr[i] = stack->arr[i-1]; } // 新元素放到栈顶(arr[0]) stack->arr[0] = value; stack->size++; return 1; }
这里一定要注意循环方向:如果从i=0开始往前挪,会把arr[0]的值覆盖到arr[1],导致原来的arr[1]数据丢失,所以必须从当前元素的末尾开始移动。
5. 出栈操作(Pop)
出栈的关键是取出arr[0]后,把后面的元素依次向前挪,保持栈顶始终在arr[0]:
// 出栈:成功返回元素值,栈空返回-1(可以根据需求调整错误处理逻辑) int pop(Stack *stack) { if (isEmpty(stack)) { printf("栈已空,无法出栈!\n"); return -1; } int topValue = stack->arr[0]; // 取出栈顶元素 // 把后面的元素依次向前挪一位 for (int i = 0; i < stack->size - 1; i++) { stack->arr[i] = stack->arr[i+1]; } stack->size--; return topValue; }
6. 获取栈顶元素(Peek)
因为栈顶固定在arr[0],直接返回它就行,记得先判断栈是否为空:
// 获取栈顶元素:成功返回值,栈空返回-1 int peek(Stack *stack) { if (isEmpty(stack)) { printf("栈已空,无栈顶元素!\n"); return -1; } return stack->arr[0]; }
测试一下代码
写个main函数验证一下逻辑是否正确:
#include <stdio.h> // 把上面的结构体和函数都放在这里 int main() { Stack stack; initStack(&stack); push(&stack, 10); push(&stack, 20); push(&stack, 30); printf("当前栈顶元素:%d\n", peek(&stack)); // 输出30(最后入栈的元素在arr[0]) printf("出栈元素:%d\n", pop(&stack)); // 输出30 printf("当前栈顶元素:%d\n", peek(&stack)); // 输出20 push(&stack, 40); printf("当前栈顶元素:%d\n", peek(&stack)); // 输出40 return 0; }
和常规栈的区别
常规栈用top下标(初始-1或0),入栈时top++直接放元素,不需要移动数据,效率更高。但你的任务要求栈顶固定在arr[0],就必须用元素移动的方式实现——这是一种 trade-off,牺牲了一点效率,但满足了特定的存储要求。
如果觉得每次移动元素太繁琐,有没有其他思路?其实也可以把数组当成“倒过来”用,但本质上还是要维护栈顶在arr[0]的逻辑,所以核心还是元素移动,毕竟位置是固定死的。
内容的提问来源于stack exchange,提问作者user9471318

