目录
序言
栈是一种特殊的数据结构,可类比为底端封口、顶端开口的容器,进去的元素都要遵循着“先进后出”的原则。栈根据实现其的存储结构可分为顺序栈和链栈。
目前我所要讲的顺序栈可看作一种变种的数组,只不过将数组的“随机存取”特性改为了“先进后出”,其实现可通过开辟一段连续的存储空间(顺序表),并定义两个指针指向,通过对这两个指针的操作来实现对不同元素的压入、弹出、获取栈顶等一系列操作!
1.有关术语说明
sequence n.顺序
Stack n.堆栈
empty adj.空的
initial adj.初始的
push v.推,压入
pull v.拉,弹出(我们也更习惯用pop)
malloc 全称memory allocation 动态内存分配
realloc 全称reset allocation 重新分配内存
2.Stack 结构体定义
typedef struct{
int *base;
int *top;
int size;
}SqStack;
定义一个栈底指针base、栈顶指针top和表示目前栈最大容量的size,特别注意,我所讲的栈的栈顶不存储元素。
3.创建 Stack
void Create(SqStack &S){
S.base=(int*)malloc(sizeof(int)*INITSIZE);
S.top=S.base;
S.size=INITSIZE;
}
创建即对结构体内的三个变量一一赋值,这里用到了一个新函数malloc()函数,是C语言中的动态内存分配函数,类似于C++中的new,不同的是malloc()需要手动计算所需内存大小,即格式为malloc(sizeof(类型名)*个数),且其返回值为一个void*类型的地址,所以还需要在其前面加上强制类型转换(类型名*),返回值为其所开辟的连续空间的首地址,所以只能赋值给指针类型变量。
4.操作
对栈的操作大致有清空Clean(SqStack &S)、销毁Destory(SqStack &S)、判断空栈Is_empty(SqStack S)、入栈Push(SqStack &S,int e)、出栈Pop(SqStack &S)、获取栈顶元素Get_top(SqStack S)、打印print(SqStack S)等操作。
此外为确保当函数结束后对参数的操作依旧会保留,这里我们对栈的个别操作函数的参数传入用了C++中的引用即&S。
4.1 清空栈Clean()
void Clean(SqStack &S){
S.top=S.base;
}
栈容量大小不变(即所开辟的存储空间没有被销毁),但栈内没有元素存入。
4.2 销毁栈Destory()
void Destory(SqStack &S){
free(S.base);
S.size=0;
}
释放栈所开辟的存储空间,并将栈容量变为0。
4.3 判断空栈Is_empty()
bool Is_empty(SqStack S){
if(S.top==S.base)return true;
else return false;
}
栈为空,返回布尔变量true,否则返回布尔变量false。
4.4 入栈Push()
void Push(SqStack &S,int e){
if(S.top-S.base>=S.size){ //当栈内元素个数大于等于栈容量(满栈)
S.base=(int*)realloc(S.base,sizeof(int)*(S.size+INCREMENT)); //realloc()函数给S.base重新分配一个更大的内存
S.top=S.base+S.size; //因为满栈即前面size-1个位置都存了元素,所以top指针指向还未存元素的第一个地址
S.size+=INCREMENT; //栈容量增加
} //当初始栈容量就很大时或者已经知道要存入元素的个数可以不考虑该情况
*S.top++=e; //因为栈顶不存储元素,将元素存入栈顶指针现在指向的位置,然后栈顶指针再上移一位
}
这里我加入了考虑满栈的情况,要用到与malloc()函数配对的realloc()函数,realloc()函数为重新分配内存函数,可在原地址上把较小的存储空间改为更大的存储空间(即存储空间首地址不变),其格式为realloc(原存储空间首地址,sizeof(类型名)*想要的空间大小(必须大于原空间大小))。
4.5 出栈Pop()
int Pop(SqStack &S){
if(S.top==S.base)return -1; //出栈失败,为空栈
else return *--S.top; //因为栈顶不存储元素,栈顶指针下移一位,然后将栈顶指针指向位置上的元素取出
}
4.6 获取栈顶元素Get_top()
int Get_top(SqStack S){
if(S.top==S.base)return -1;
else return *--S.top;
}
与出栈操作类似,唯一的区别是函数参数传入,因为获取栈顶元素操作不能改变栈结构,所以函数参数传入没有用引用,当函数结束时对S的操作不会保留,但返回值却可以被我们获取。
4.7 打印栈print()
void print(SqStack S){
int *p=S.base;
while(p<S.top){
printf("%d ",*p);
p++;
}
printf("\n");
}
5.主函数main()
int main(){
SqStack S;
Create(S);
if(Is_empty(S))printf("为空栈!\n");
else printf("不为空栈!\n");
Push(S,5);
Push(S,3);
Push(S,1);
Push(S,4);
Push(S,2);
print(S);
printf("栈顶元素:%d\n",Get_top(S));
print(S);
Pop(S);
Pop(S);
print(S);
if(Is_empty(S))printf("为空栈!\n");
else printf("不为空栈!\n");
Clean(S);
if(Is_empty(S))printf("为空栈!\n");
else printf("不为空栈!\n");
Destory(S);
return 0;
}