1.何为栈?
栈是数据结构中的一种,他也是一种线性表,与顺序表类似。对于栈来说,他是一种"先入后出"的一种数据结构,也就是说,最后进入到栈里面的元素,在被操作者访问的时候,是最先访问最后进栈的元素的。
2.实现栈
(1).定义栈
与顺序表一样,栈的定义是首先用数组来组成,因此结构体里会有一个数组的首元素,空间和栈顶。
typedef struct Stack
{
StDataType* num;
int capacity;
int top;
}ST;
(2).栈的初始化和销毁
对于栈的初始化这个问题,在初始化top的时候,有两种选择,一种是把top初始化为0,另一种是把top初始化为-1。这两种所代表的含义都是不一样的,前者是当top为0时,top指向的是栈顶元素的下一个;而当top为-1时,top则是刚好指向栈顶元素。在这篇博客中,我将会把top的初始值设置成为-1,统一理解。
因此就有了这个代码。
初始化:
void STInit(ST* pst)
{
assert(pst);
pst->capacity = 0;
pst->num = NULL;
pst->top = -1;
}
销毁:
void STDestory(ST* pst)
{
assert(pst);
pst->capacity = 0;
pst->num = NULL;
}
(3).压栈
压栈顾名思义,就是对栈内进行插入元素,而栈的性质又决定了栈只能在其一端进行操作。因此用数组栈,可以使用下标对其进行控制,是比较方便的一个选择。而压栈的整体思路是直接令将要入栈的元素等于pst->num[pst->top]就行了。由于我的pst->top一开始的初始值是-1,而在数组下标中是没有-1这个东西存在的,这会导致数组越界。因此在压栈前,要把pst->top进行++,让top变成0.
void Push(ST* pst, StDataType x)
{
if (pst->capacity == pst->top + 1)
{
int Newcapacity = pst->capacity == 0 ? 5 : pst->capacity * 2;
StDataType* tmp = realloc(pst->num, sizeof(StDataType) * Newcapacity);
if (tmp == NULL)
{
perror("new capacity realloc fail!");
return 1;
}
pst->num = tmp;
pst->capacity = Newcapacity;
}
pst->top++;
pst->num[pst->top] = x;
}
在元素入栈前,都会对栈进行一个空间大小的判断。如果capacity == top+1,则说明栈已经满了,因此需要扩容。而扩容的思路,则是首先判断capacity == top+1这两个是否相等,如果相等,则进入if语句,定义一个newcapacity,让他等于当前的capacity,如果当前的capacity == 0,就说明他里面没有任何元素,就给5,如果不是,就给自身*2.然后使用realloc对其进行扩容,把扩容后的新空间赋给pst->num,然后把新空间赋给pst->capacity。最后在入栈前,得先对top进行一次++(因为top一开始的值是-1).
(4).删除和弹出访问
栈的删除,思路也是非常简单,直接把下标往回--一次就可以了。
void Pop(ST* pst)
{
assert(pst);
assert(pst->top > -1);
pst->top--;
}
而弹出访问,则是由栈的性质决定的,栈的访问只能是一个接一个的访问,弹出后,这个元素就不在栈里面了。
void Top(ST* pst)
{
assert(pst);
assert(pst->top > -1);
printf("%d ", pst->num[pst->top]);
pst->top--;
}
(5).栈的判空
由于我们是使用数组栈,因此若想判空也是一个非常简单的思路,就直接看下标是否是-1,如果是-1,则栈里面就没有任何的元素。
bool STEmpyt(ST* pst)
{
assert(pst);
return pst->top == -1;
}
bool类型的函数,返回pst->top == -1。如果这句话是真,那就代表栈里面是没有元素的,否则反之。
(6).栈长度的判断
没啥好说的....
int STSize(ST* pst)
{
assert(pst);
return pst->top + 1;
}