一、C语言顺序栈的操作(明确栈顶所指向的此时此刻没有数据)
0)定义----顺序栈定义和一些宏定义
#define MaxSize 10 //最大容量
#define AddSize 2 //增加的容量
#define ElementType int //元素类型,每个元素的输入都会有空格进行分割,不管是字符还是整型
#define LEN sizeof(Element) //栈的一个元素的空间
#define EndChar 0 //结束入栈的字符标识
//顺序栈
typedef struct{
ElementType * Top;//栈顶
ElementType * Base;//栈底
int maxsize;//最大容量
}SqStack;
1)创建----开辟一段连续的内存空间,如果创建成功就让栈顶指针和栈底指针相同,并赋值结构体中的maxsize成员,如果创建失败(情况很少)就提示用户并终止运行
//初始化
void InitStack(SqStack* stack){
stack->Base=(ElementType *)malloc(LEN*MaxSize);//开辟一段连续的内存空间,指向的是元素类型的指针
if(stack->Base==NULL){
printf("初始化栈出错!\n");
exit(0);//退出程序
}
stack->Top=stack->Base;
stack->maxsize=MaxSize;
printf("初始化栈成功!\n");
}
2)入栈----入栈时我们首先要判断栈是否为满栈,如果为满栈我们有两种选择一种是放弃追加存储空间并显示当前栈的内容另一种是继续追加存储空间,然后才能将元素入栈;如果此时不为满栈就继续入栈,并且要注意是先入栈然后指针才偏移。realloc()函数详解请看realloc详解
//入栈,时时刻刻判断是否满了,满了再判断是否要重新开辟
void StackPush(SqStack* stack,ElementType element){
//满了
if(stack->Top-stack->Base>=stack->maxsize){
printf("\n栈已满了!\n");
printf("\n是否增大栈的容量?输入Y/y表示是,其它表示否:");
fflush(stdin);//由于可能输入的是过长的,把没有读取的留在缓冲区的清除掉
char c;
scanf("%c",&c);
getchar();//接收回车,以免发生Bug
if(c=='Y'||c=='y'){
printf("你选择的是增加栈的容量!\n");
stack->Base=(ElementType *)realloc(stack->Base,(stack->maxsize+AddSize)*LEN);//该函数开辟的空间的首地址不变
if(stack->Base==NULL){
printf("\n栈容量增加操作失败!\n");
exit(0);
}
//更新
stack->Top=stack->Base+stack->maxsize;
stack->maxsize+=AddSize;
}
else{
printf("\n你选择的是不增加栈的容量,入栈结束!\n");
ShowStack(stack);
return;
}
}
//没满
else{
*(stack->Top)=element;//*运算优先级高于++,先进入后偏移
printf("\n%d入栈成功!\n",*(stack->Top));//这样可以明确知道是不是真的入栈了
stack->Top++;
}
}
3)出栈----出栈时我们首先要判断栈是否为空栈,如果栈已经空了打印提示语句。要注意是指针先偏移然后出栈
//出栈,时时刻刻判断是否为空
void StackPop(SqStack* stack,ElementType * element){
if(stack->Base==stack->Top){
printf("出栈失败,栈已空!\n");
return;
}
*element=*--(stack->Top);//先偏移后弹出
printf("弹出的元素是:%c\n",*element);
}
4)显示栈内容----这里是显示从栈底到栈顶的元素,要注意栈的成员不能有改变,所以这里用了一个中间变量
//显示栈的内容,从底到顶
void ShowStack(SqStack* stack){
ElementType * Temp=stack->Base;
int i=1;
printf("\n栈的内容如下\n");
while(Temp!=stack->Top){
printf("第%d个元素是:%c\n",i++,*Temp++);
}
}
5)计算栈当前容量----指针相减的结果其实是内部多作了一个运算,也就是(p1-p2)/(指针所指向的数据类型所占的字节),比如两个指针指向int型,p1=0x00,p2=0x08,则p2-p1的结果编译器会给2
//返回栈的元素个数
int StackLength(SqStack stack){
return (stack.Top-stack.Base);
}
6)判断是否为空----跟5)做法类似
//判断栈是否为空
void StackEmpty(SqStack stack){
if(stack.Top==stack.Base){
printf("\n此栈为空!\n");
}
else{
printf("\n此栈不为空!\n");
}
}
7)清空----物理内存还在,让栈顶跟栈底相同,这样栈里面的内容虽然没有丢失,但是下次入栈后原本的数据会被覆盖所以类似清空栈的效果
//清空一个栈
void ClearStack(SqStack* stack){
stack->Top=stack->Base;
printf("\n清空栈成功!\n");
}
8)销毁----要释放物理内存,也就是每个栈的元素都要进行释放,并且对结构体的成员重新赋值,并提示用户
//销毁一个栈,从下往上销毁
void DestroyStack(SqStack* stack){
while(stack->Base!=stack->Top){
free(stack->Base);
stack->Base++;
}
stack->Base=stack->Top=NULL;
stack->maxsize=0;
printf("\n销毁栈成功!\n");
}
二、实践
主函数实现的是:
1)变量的定义
2)提示用户的语句
3)初始化栈
4)入栈
5)结束入栈的提示语句
6)显示入栈结束后栈的内容
7)出栈并显示每次出栈的内容
8)销毁栈并判断是否为空栈
#include
#include
//如果要修改入栈的数据类型,只需改一个元素类型宏定义和结束的标识符,入栈出栈末尾的printf,ShowStack函数中printf,主函数的一些scanf和printf
#define MaxSize 10 //最大容量
#define AddSize 2 //增加的容量
#define ElementType int //元素类型,每个元素的输入都会有空格进行分割,不管是字符还是整型
#define LEN sizeof(ElementType) //栈的一个元素的空间
#define EndChar 0 //结束入栈的字符标识
//顺序栈
typedef struct{
ElementType* Top;//栈顶
ElementType* Base;//栈底
int maxsize;//最大容量
}SqStack;
//初始化
void InitStack(SqStack* stack){
stack->Base=(ElementType*)malloc(LEN*MaxSize);//开辟一段连续的内存空间,指向的是元素类型的指针
if(stack->Base==NULL){
printf("初始化栈出错!\n");
exit(0);//退出程序
}
stack->Top=stack->Base;
stack->maxsize=MaxSize;
printf("初始化栈成功!\n");
}
//判断栈是否为空
void StackEmpty(SqStack stack){
if(stack.Top==stack.Base){
printf("\n此栈为空!\n");
}
else{
printf("\n此栈不为空!\n");
}
}
//返回栈的元素个数
int StackLength(SqStack stack){
return (stack.Top-stack.Base);
}
//清空一个栈
void ClearStack(SqStack* stack){
stack->Top=stack->Base;
printf("\n清空栈成功!\n");
}
//销毁一个栈,从下往上销毁
void DestroyStack(SqStack* stack){
while(stack->Base!=stack->Top){
free(stack->Base);
stack->Base++;
}
stack->Base=stack->Top=NULL;
stack->maxsize=0;
printf("\n销毁栈成功!\n");
}
//显示栈的内容,从底到顶
void ShowStack(SqStack* stack){
ElementType* Temp=stack->Base;
int i=1;
printf("\n栈的内容如下\n");
while(TempTop){
printf("第%d个元素是:%d\n",i++,*Temp++);
}
}
//入栈,时时刻刻判断是否满了,满了再判断是否要重新开辟
void StackPush(SqStack* stack,ElementType element){
//满了
if(stack->Top-stack->Base>=stack->maxsize){
printf("\n栈已满了!\n");
printf("\n是否增大栈的容量?输入Y/y表示是,其它表示否:");
fflush(stdin);//由于可能输入的是过长的,把没有读取的留在缓冲区的清除掉
char c;
scanf("%c",&c);
getchar();//接收回车,以免发生Bug
if(c=='Y'||c=='y'){
printf("你选择的是增加栈的容量!\n");
stack->Base=(ElementType*)realloc(stack->Base,(stack->maxsize+AddSize)*LEN);//该函数开辟的空间的首地址不变
if(stack->Base==NULL){
printf("\n栈容量增加操作失败!\n");
exit(0);
}
//更新
stack->Top=stack->Base+stack->maxsize;
stack->maxsize+=AddSize;
}
else{
printf("\n你选择的是不增加栈的容量,入栈结束!\n");
ShowStack(stack);
return;
}
}
//没满
else{
*(stack->Top)++=element;//*运算优先级高于++,先进入后偏移
printf("\n%d入栈成功!\n",element);
}
}
//出栈,时时刻刻判断是否为空
void StackPop(SqStack* stack,ElementType* element){
if(stack->Base==stack->Top){
printf("出栈失败,栈已空!\n");
return;
}
*element=*--(stack->Top);//先偏移后弹出
printf("弹出的元素是:%d\n",*element);
}
int main(){
//定义变量
SqStack stack;
ElementType Temp=0;//随便赋值不要给'#'就行
//提示语句
printf("提示:请输入要入栈的内容,并且每个要入栈的元素中间用空格隔开,以#作为结束标识,回车和空格不会入栈!\n\n");
//初始化
InitStack(&stack);
//入栈
scanf("%d",&Temp);
while(Temp=='\n'||Temp==' ') scanf("%d",&Temp);//第一个字符要保证不是回车和空格
while(Temp!=EndChar){
if(Temp!='\n'&&Temp!=' '){//回车字符和空格字符不要入栈
StackPush(&stack,Temp);
}
scanf("%d",&Temp);
}
//退出方式有两种,一种是输入了结束标识符,另一种是栈满但是不增加
if(Temp==EndChar){
printf("\n按下了结束标识符,入栈结束!\n");
}
//显示入栈完成后的信息
ShowStack(&stack);
//让页面好看点
printf("\n");
//显示弹出的元素
while(StackLength(stack)){
StackPop(&stack,&Temp);
}
//销毁
DestroyStack(&stack);
StackEmpty(stack);
return 0;
}