顺序栈元素‘"入栈":
比如,还是模拟栈存储 {1,2,3,4}
的过程。最初栈是"空栈",top 的值为 -1,如图1 所示:
将元素 1 入栈,默认数组下标为 0 一端表示栈底,元素 1 存储在数组 a[0] 处,同时 top 值 +1,如图 2 所示:
采用同样的方式,依次将元素 2、3 和 4 入栈,最终 top 的值变成 3,如图3 所示:
因此,C 语言实现代码为:
//元素elem进栈,a为数组,top值为当前栈的栈顶位置 int push(int* a,int top,int elem){ a[++top]=elem; return top; }
代码中的 a[++top]=elem,等价于先执行 ++top,再执行 a[top]=elem。
顺序栈元素"出栈":
实际上,top 变量的设置对模拟数据的 "入栈" 操作没有帮助,它是为实现数据的 "出栈" 操作做准备的。
比如,将图3 中的元素 2 出栈,则需要先将元素 4 和元素 3 依次出栈。需要注意的是,当有数据出栈时,要将 top 做 -1 操作。因此,元素 4 和元素 3 出栈的过程分别如图 6a) 和 6b) 所示:
元素 4 和元素 3 全部出栈后,元素 2 才能出栈。因此,使用顺序表模拟数据出栈操作的 C 语言实现代码为:
//数据元素出栈 int pop(int * a,int top){ if (top == -1) { printf("空栈"); return -1; } printf("弹栈元素:%d\n",a[top]); top--; return top; }
代码中的 if 语句是为了防止用户做 "栈中已无数据却还要做出栈操作" 的错误操作。细心的读者还可能发现,出栈操作只是将 top 的值减 1,并没有像图 4 那样将出栈元素从数组中手动删除。这是因为,当有新的元素入栈后,新元素会将出栈元素覆盖掉,所以不删除出栈元素,也不会影响栈的正常使用,何必多此一举。
总结:
通过学习顺序表模拟栈中数据入栈和出栈的操作,初学者完成了对顺序栈的学习,这里给出顺序栈及对数据基本操作的 C 语言完整代码:
#include <stdio.h> //元素elem进栈 int push(int* a, int top, int elem) { a[++top] = elem; return top; } //数据元素出栈 int pop(int* a, int top) { if (top == -1) { printf("空栈"); return -1; } printf("弹栈元素:%d\n", a[top]); top--; return top; } int main() { int a[100]; int top = -1; top = push(a, top, 1); top = push(a, top, 2); top = push(a, top, 3); top = push(a, top, 4); top = pop(a, top); top = pop(a, top); top = pop(a, top); top = pop(a, top); top = pop(a, top); return 0; }
程序输出结果为:
弹栈元素:4
弹栈元素:3
弹栈元素:2
弹栈元素:1
空栈
链栈元素入栈:
例如,依次将 1、2、3、4 存储到栈中,每个元素的入栈过程如图 1 所示:
C语言实现代码为:
//链表中的节点结构 typedef struct lineStack { int data; struct lineStack* next; }LineStack; //stack为当前的链栈,a表示入栈元素 LineStack* push(LineStack* stack, int a) { //创建存储新元素的节点 LineStack* line = (LineStack*)malloc(sizeof(LineStack)); line->data = a; //新节点与头节点建立逻辑关系 line->next = stack; //更新头指针的指向 stack = line; return stack; }
链栈元素出栈:
在图1) 所示链表的基础上,假设将元素 3 从栈中取出,根据"先进后出"的原则,要先将元素 4 出栈,然后元素 3 才能出栈,整个操作过程如图2 所示:
实现栈顶元素出栈的 C 语言代码为:
//栈顶元素出链栈的实现函数 LineStack* pop(LineStack* stack) { if (stack) { //声明一个新指针指向栈顶节点 LineStack* p = stack; //更新头指针 stack = stack->next; printf("出栈元素:%d ", p->data); if (stack) { printf("新栈顶元素:%d\n", stack->data); } else { printf("栈已空\n"); } free(p); } else { printf("栈内没有元素"); return stack; } return stack; }
代码中通过使用 if 判断语句,避免了用户执行"栈已空却还要数据出栈"错误操作。
总结:
本节,通过采用头插法操作数据的单链表实现了链栈结构,这里给出链栈及基本操作的C语言完整代码:
#include <stdio.h> #include <stdlib.h> //链表中的节点结构 typedef struct lineStack { int data; struct lineStack* next; }LineStack; //stack为当前的链栈,a表示入栈元素 LineStack* push(LineStack* stack, int a) { //创建存储新元素的节点 LineStack* line = (LineStack*)malloc(sizeof(LineStack)); line->data = a; //新节点与头节点建立逻辑关系 line->next = stack; //更新头指针的指向 stack = line; return stack; } //栈顶元素出链栈的实现函数 LineStack* pop(LineStack* stack) { if (stack) { //声明一个新指针指向栈顶节点 LineStack* p = stack; //更新头指针 stack = stack->next; printf("出栈元素:%d ", p->data); if (stack) { printf("新栈顶元素:%d\n", stack->data); } else { printf("栈已空\n"); } free(p); } else { printf("栈内没有元素"); return stack; } return stack; } int main() { LineStack* stack = NULL; stack = push(stack, 1); stack = push(stack, 2); stack = push(stack, 3); stack = push(stack, 4); stack = pop(stack); stack = pop(stack); stack = pop(stack); stack = pop(stack); stack = pop(stack); return 0; }
程序运行结果为:
弹栈元素:4 栈顶元素:3
弹栈元素:3 栈顶元素:2
弹栈元素:2 栈顶元素:1
弹栈元素:1 栈已空
栈内没有元素