顺序栈

#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; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值