69,374
社区成员
发帖
与我相关
我的任务
分享
#include <stdio.h>
#include <stdlib.h>
/*数组实现栈*/
#define MAXSIZE 256
/*程序命名风格,要么都用大写开头,命名类型和函数,要么都用小写
与厦门的sqstack, pop等保持一致,不要混用两种风格
*/
typedef int elemtype;
typedef struct list
{
elemtype *bottom; //命名规范,bottom 对top,,high对low,,
elemtype *top; //既然想通过typedef 来方便修改类型就统一用这个,而不是int*
int capability; //栈的总容量,不是栈中元素个数
}sqstack;
/*
1 变量命名用小写,不要大写
2 sqstack *s 用指针, 就已经表示传的是地址了, 指针变量是变量的一种
都是这么定义的,而不是用&s
调用的时候才用取地址符号
比如 sqstack stack_test;
init(&stack_test)
*/
/*考虑到栈有建立,就要有响应的销毁过程与之对应
以便释放内存,这里将init改成create,
同时新增destroy函数*/
/*
return: 0成功, 1 失败
不要对同一个s重复调用,否则会内存泄漏
*/
int create(sqstack *s)
{
s->bottom = (elemtype *)malloc(MAXSIZE * sizeof(elemtype)); //*申请连续空间----,而不是申请一个
if(!s->bottom){ //等价于 if(s->bottom == NULL)
printf("malloc memory error\n");
return 1;
}
s->top = s->bottom; //指针访问成员,用箭头->,而不是.
s->capability = MAXSIZE;
return 0; //
}
/*要求使用者很小心,必须是成功create过的s,才能调用*/
void destroy(sqstack *s)
{
if(s->bottom) //bottom是不变的,用于记录申请的空间,
{
free(s->bottom);
s->bottom = NULL;
}
return;
}
int push(sqstack *s, elemtype e)
{
/*指针让人产生歧义的地方,有时候图方便,你会想当然的认为,要取栈顶元素,直接拿top就是了
* 事实上,要取栈顶元素的时候,是top-1,而不是top!!
* 既然top开始指向可放元素的地方,即入栈位置,那么他表示top入完栈之后,你把他加1, 显然top指示的是一个未知元素,,,
* 继续看后面的实现,就知道top指针多尴尬
*/
if(s->top - s->bottom == s->capability)
{
//栈满了,扩容
printf("stack full, realloc a larger space\n");
elemtype *new_ptr = (elemtype *)realloc(s->bottom, s->capability * 2);
if(new_ptr == NULL)//重新分配失败,原来的保留
{
printf("fail to realloc more memory\n");
return 1;
}
s->bottom = new_ptr;
s->capability = 2 * s->capability;
}
*s->top++ = e;
return 0;
}
/*
return : 0 ok, 1 err 栈为空,无法再弹出(pop)元素出来
*/
int pop(sqstack *s, elemtype *e)
{
if(s->top == s->bottom)
{
printf("stack is empty\n");
return 1;
}
*e = *--s->top;
return 0;
}
/*自顶向下打印栈*/
void printstack(sqstack *s)
{
/*
这里要减1,用简单情况进行推理
比如栈只有1个元素的时候,这个元素就在第0个位置
C语言连续内存,比如数组,总是从0开始
*/
if(s->top == s->bottom)
{
printf("stack is empty, nothing in it\n");
return;
}
printf("print stack s from top to bottom\n");
elemtype *itor = s->top; //因为只是打印,不要去改变这个栈,所以用临时变量来进行遍历
while (itor != s->bottom) //虽然是很不好的风格,,谁让你用指针呢, 而且指针绕到你头疼
{
/*这里假定elemtype 是int(用%d打印),这就是C语言麻烦的地方
先不多扯了,想想如果是double,是不是要另外写函数,
一般要用函数指针来实现,你先了解下就好*/
/*%d 后面有空格,2d表示用两个位置来打印一个数,
额额,如果3位数? 3d,如果不确定几位,那就不对齐了,,,
这里只是在对比的时候能对齐,好看*/
printf("%2d ", *--itor); //如果用 *--s->top;,,那你一边打印,一遍出栈了。。。
}
printf("\n"); //换行
}
/*反转栈
虽然这样写比较没效率,但是想象一下
你有一叠盘子,嗯,底下的盘子大,上面的盘子小
现在,你从顶部开始一个一个拿下来,一次叠到另外一个地方,想象一下
- ----
-- --> ---
--- --
---- -
*/
/*略去了错误处理,你可以考虑下,可能哪里会异常
为了配合create,并演示上面的过程,这个实现显得有些古怪,你习惯就好*/
void reverse(sqstack *s)
{
sqstack tmp; //你把盘子拿出来,总得有地方放,弄一个tmp栈来接纳他
create(&tmp);
/*反转的过程*/
while(s->top != s->bottom)
{
elemtype e;
pop(s, &e); //出栈,弹出元素暂时放到e
push(&tmp, e); //入栈,盘子从s拿出来,放到tmp,一次循环拿一个
//这里不用执行s->size --, tmp->size++ 因为在pop和push中做了
}
/*到这里,已经成功把元素搬到tmp了,,,
本来规范一点的做法是把新的栈返回给调用者,但是为了沿用你定义的接口
咱们偷梁换柱一下,把内存互换,内存就是容器,想象一下,两叠盘子底下都有个篮子用来装他们
假设篮子都贴着标签,第一个篮子签写着A, 搬动后放到篮子B上面,
问:你如何在不搬动盘子的情况下,让这叠盘子依然在篮子A里面呢(盘子都从A搬到B了)
聪明的你也许已经想到答案了,把篮子B的标签撕下来,然后把篮子A的标签贴到B上,
很流氓是不是?下面的代码就是这么干的 s->bottom就是这个所谓的标签
*/
elemtype *labtmp; //什么? 换个标签也这么麻烦?要找个地方现暂放一下,而不是把A直接贴到B上
labtmp = s->bottom; //想象一下,把A撕了,暂时贴到一块干净的玻璃上吧,免得把上面的胶水粘没了
s->bottom = tmp.bottom; //既然A撕掉了,B可以直接贴过来了,A篮子变成了标签B
tmp.bottom = labtmp; //原来的标签A贴过去,偷梁换柱完成。
s->top = tmp.top; //别忘记还有这个
/*至此完成反转 打印出来验证下看*/
//printf("after reverse:\n");
//printstack(s);
destroy(&tmp); //别忘了tmp只是暂时借来放东西的,把他释放掉吧,
/*再次强调,这并不是一个很好的实现,只是为了知识点简单一些,不引入更复杂的技巧的情况下的无奈之举*/
}
int main ()
{
sqstack s;
int e; //从数字几开始入栈
int count; //推几个数字入栈
char buf[256]; //存放用户输入
printf("enter the start num:\n");
fgets(buf, 256, stdin); //stdin 表示标准输入
e = atoi(buf); //字符串解释成整型
printf("enter the total count \n");
fgets(buf, 256, stdin);
count = atoi(buf);
if(create(&s) != 0){
return -1;
}
while(count > 0)
{
push(&s, e);
e++;
count--;
}
printf("origin stack :\n");
printstack(&s);
reverse(&s);
printf("after reverse:\n");
printstack(&s);
destroy(&s);
return 0;
}
附上我在linux环境下的编译运行过程
顺带说一下,你要注意提问题的方式,提问的时候,最好是源代码复制上来,而不是贴图
这样别人在阅读和修改你的代码都会很方便,千万千万别截图,这是尊重他人的体现。
想让人帮忙,但是截图简直是浪费别人时间。
感觉CSDN这个社区已经运营得烂掉了,没人在乎你是否截图提问,只知道骗人买会员,,