说到栈,相信大家肯定多少都有听说过吧!C语言里的函数在进行调用时便是借助系统中的“栈”结构,其次生活中也有许多栈的应用实例,最容易想象的就是弹夹了,弹夹的结构就是“栈”的应用之一。说完实例,相信大家也能看出“栈”的特性了吧~那就是“后进先出(Last in First out)”。
- 栈其实本质上也是属于线性表,只不过是较为特殊的线性表,与其特性相匹配的还有队列,队列也是特殊的线性表之一,我们在下一篇会为大家介绍。
- 栈呢大体即分为:栈顶、栈底,无论是入数据还是出数据,都需要通过栈顶,因此这也保证了它的特性“后进先出”:先进去的会被压在栈底,而后进去的则是在栈顶。
- 对栈进行数据的插入操作即被称作入栈(压栈),删除数据的操作被称作出栈。
关于模拟实现栈
实现栈可以使用数组/链表都行(按需灵活使用):
1. 数组实现栈:
数组的首位做栈底,尾部做栈顶,入数据即等同于尾插数据,出数据即等于尾删数据 数组比较合适,唯一缺陷就是要增容
2.链表实现栈:
链表的话,单链表如果是尾作栈顶,尾删效率比较低,所以建议使用双向带头循环链表 如果要用单链表,则使用头作栈顶即可
由于数组实现较为便捷,故本篇模拟实现的是用数组实现的栈,如果大家感兴趣也可自行去尝试用链表去实现栈,其实难度也算相当。
接下来即看如何自己模拟实现一个栈结构吧
首先还是先来看看整体的栈结构是怎么样的
typedef int STDataType; typedef struct Stack { STDataType *stack; int size; int top; int capacity; }Stack;
整体结构即包括了一个可动态增长的数组模拟的栈帧空间、栈内的数据个数、栈顶位置以及栈容量等,这即是最基本的一个栈结构。
首先还是需要对栈进行一个简单的初始化操作:init_stack()
void StackInit(Stack *ST) { STDataType *tmp = (STDataType*)malloc(sizeof(STDataType)*4); assert(tmp); ST->stack = tmp; ST->size = 0; ST->capacity = 4; ST->top = -1; }
我们可以看到初始化时,我们将栈顶初始化为-1,这是因为插入数据时,数组首元素下标为“0”,当然也可以初始化为“0”,那么注意进行操作时需要对应做出一点变化。
初始化完栈之后就是对栈的操作了:添加数据、删除数据等
添加数据:push()
void push(Stack *ST,STDataType x) { assert(ST); if(ST->size == ST->capacity) { STDataType *tmp = (STDataType*)realloc(ST->stack,sizeof(STDataType)*ST->capacity*2); assert(tmp); ST->stack = tmp; ST->capacity *= 2; } ST->stack[ST->size] = x; ST->size++; ST->top++; }
入数据即是直接往数组中添加数据即可。
删除数据:pop()
void pop(Stack *ST) { assert(ST); assert(ST->top >= 0); ST->size--; ST->top--; }
删除数据时由于是用数组结构作为栈结构,所以直接将数据容量减一即可(相当于尾删)
剩下的一些就是简单的接口用于栈的辅助使用:返回栈顶数据、返回栈空间容量、判断栈是否为空以及销毁栈空间
返回栈顶数据:top()
STDataType top(Stack *ST) { assert(ST); assert(ST->top >= 0); return ST->stack[ST->top]; }
直接返回栈顶指针对应的数据即可
返回栈空间容量:size()
int size(Stack *ST) { assert(ST); return ST->size; }
栈结构设计时即包含了栈的容量,其随着栈的数据个数相应变换,所以直接返回即可
判断栈是否为空:empty()
bool empty(Stack *ST) { assert(ST); return ST->top == -1; }
由于我们最开始的栈顶指针指向“-1”的位置,所以如果栈顶指针指向的位置是初始位置,该栈即为空
销毁栈空间:destroy()
void StackDestroy(Stack *ST) { assert(ST); free(ST->stack); ST->size = 0; ST->capacity = 0; ST->top = -1; ST->stack = NULL; }
销毁时,将动态开辟的空间释放以及其它数据量进行初始化即可
整体通过数组结构对栈的模拟实现, 可以看到并没有什么复杂的地方,都是对数组进行特定化操作,让数组满足栈的使用特点即可。
如果本篇文章对你有帮助的话,可以顺带点个赞即收藏哩~