#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1 //不可操作的 不可行的
#define OVERFLOW -2
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef int ElemType; //最好的做法是同义声明一个ElementType 便与修改
typedef int Status; //既然说 函数返回有不同的情况 定义status是比较合理的
/*关于引用 实际上 指针传递是可以的
但是 你指针变量出了函数后就回收了 所以如果不用引用传递 就必须要返回给被拷贝的变量 进行更新
多看看别人的规范代码 自己也学习怎么写才算尽量规范 合理
栈的操作除了使用这种结构体实现 这个结构体 其实可以不用本质上 还是数组 通过指针来操作
还可以静态数组和动态数组实现
动态数组 长度可变 灵活增强 realloc
在某些场合 栈大小固定 可以使用静态数组实现栈
*/
typedef struct {
ElemType *base; //栈底指针
ElemType *top; //栈顶指针
int stacksize; //栈顶长度
}SqStack; //顺序栈结构定义
// 初始化
Status InitStack(SqStack &s){
s.base =(ElemType*)malloc(STACK_INIT_SIZE*sizeof(ElemType));
if(!s.base){
exit(OVERFLOW);//存储分配失败
}
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
return OK;
}
// 清空栈 其实 栈里面的元素时没有置0的 只是那个地方的数据不在栈的范围之内了 以后入栈会被更新
Status ClearStack(SqStack &s){
s.top = s.base;
//长度改变为0
s.stacksize = 0;
return OK;
}
// 摧毁栈 回收内存 野指针回收
Status DestroyStack(SqStack &s){
s.top = NULL; //防止出现野指针
s.stacksize = 0; // 你们觉得 这个是有必要的吗? 不置零有关系吗?
//本来是没多大关系的 只是一个变量而已 可是如果说你要重新操作创建一个栈 这个程序设计为可循环操作
// 那么 stacksize 就需要 或者说 应该为零
free(s.base); //回收内存空间
return OK;
}
// 判空
Status StackEmpty(SqStack s)
{
if (s.top == s.base)
return ERROR;
else
return TRUE;
}
// 求长度 不需要引用传递 因为只是把长度求出来 没改变栈
Status GetStackLength(SqStack s){
if(s.top == s.base)
return FALSE;
else{
//printf("%d",s.top - s.base);
return (s.top - s.base);
}
}
//获取栈顶元素
Status GetTop(SqStack &s,ElemType &e){
if(s.top == s.base)
return FALSE;
else
return (e = *(s.top - 1));
}
// 入栈操作
Status Push(SqStack &s,ElemType &e){
if(s.top - s.base >= STACK_INIT_SIZE){
s.base = (ElemType *)realloc(s.base,(s.stacksize + STACKINCREMENT)*sizeof(ElemType));
//新的大小一定要大于原来的大小,不然的话会导致数据丢失
if(!s.base)
return FALSE;
s.top = s.base + s.stacksize;//栈底地址可能改变??? 重新定位栈顶元素
s.stacksize += STACKINCREMENT;
}
*s.top = e;
s.top++;
return OK;//入栈就不用返回元素了 出栈是可以的
}
// 出栈操作
Status Pop(SqStack &s, ElemType &e)
{
if (s.top == s.base)
return ERROR;
else
{
s.top--; //top是栈顶 也就是 指向最上面元素的上面一个位置
e = *s.top;
//说明:此处容易使人迷惑,实际上此元素并没真正删除,仍在S.top中,
//但是如果插入元素,就会被更新,就像是删除了一样
return e;
}
}
// 遍历操作
Status TravelStack(SqStack s){
if (s.base == NULL)
return ERROR;
if (s.top == s.base)
printf("栈中没有元素\n");
ElemType *p; //int
p = s.top;
while (p > s.base)
{
p--;
printf("%d ",*p);
}
return OK;
}
int main(){
SqStack s;
printf("构造一个空栈……\n");
InitStack(s);
int i,n;//必备变量
printf("输入栈的长度:");
scanf("%d",&n);
//按理说 也可以 或者说这里应该写一个函数单独完成指定初始化
for (i = 1; i <= n; i++)
{
printf("输入栈的第%d个元素:",i);
++s.top;
printf("%d",s.top);
scanf("%d",&(*(s.top-1)));
}
//做个小测试呗
printf("……本栈是空栈吗??……\n");
if (StackEmpty(s) == 1)
printf("NO !!!\n");
else
printf("yes!!!\n");
printf("……求出栈的长度……\n");
int m;
// printf("%d",s.base);
// printf("%d",s.top);
m = GetStackLength(s);
printf("栈的长度是: %d \n",m);
printf("遍历输出栈中的所有元素:");
TravelStack(s);
printf("\n……输出栈顶元素……\n");
int e;
e = GetTop(s, e);
printf("栈顶元素是: %d\n" ,e);
printf("……栈顶插入元素……\n");
printf("请输入要插入的元素的数值:");
scanf("%d",&e);
Push(s,e);
printf("现在栈中的元素是:");
TravelStack(s);
printf("\n");
printf("……栈顶删除元素……\n");
e = Pop(s,e);
printf("被删除的元素是: %d\n",e);
printf("现在栈中的元素是:");
TravelStack(s);
printf("\n");
printf("……清空栈……\n");
ClearStack(s);
printf("现在栈中的元素是: \n" );
TravelStack(s);
printf("……销毁栈……\n");
if(DestroyStack(s)==1)
printf("销毁栈成功\n");
else
printf("销毁栈失败\n");
printf("恭喜您成功完成所有的功能,毕竟您那么帅!!!");
return 0;
}
顺序栈
最新推荐文章于 2024-09-13 19:08:00 发布