CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C语言

栈应用详解(由一个例子学习栈)学习栈的朋友请进!

楼主rerli(Brooks)2003-12-02 14:58:23 在 C/C++ / C语言 提问

/*  
  作者:rerli  
  时间:2003-12-02  
  目的:由一个例子学习栈。  
   
  栈应用详解:  
  用栈改递归为非递归,计算Ackermann函数A(n,x,y)。  
   
  */  
   
   
  #include   <stdlib.h>  
  #include   <stdio.h>  
  #define   NULL   0  
   
  typedef   struct   node  
  {  
  int   n;  
  double   x;  
  double   y;  
  }NODE;  
   
  #define   LEN   sizeof(NODE)  
   
  /*栈的需要变量*/  
  typedef   enum   {false,true}bool; /*定义bool类型*/  
  static   NODE   *p_stack; /*定义栈指针变量*/  
  static   NODE   *stack; /*定义一个栈*/  
  static   unsigned   int   stack_size; /*栈的大小*/  
   
  /*  
                    栈空                   出栈前                 出栈后  
                |           |                 |           |                               |           |  
                |_____|   p_stack--->|_____|                               |_____|  
                |_____|                 |__1__|           p_stack--->|__1__|  
  p_stack--->|_____|                 |__0__|               |__0__|  
   
  从上图可知出栈后,栈顶指针指向的是刚才出栈元素的首地址。  
  若POP()栈顶值,此时的*p_stack和刚才pop()出来的值一模一样。  
   
  */  
   
   
  /*  
  功能:初始化栈的大小  
  返回:true   or   false  
  */  
  bool   init_stack(unsigned   int   size)  
  {  
  stack=(NODE   *)malloc(size*LEN);                      
  if   (stack==NULL)  
  {  
  return   false;  
  }  
  stack_size=size;  
  p_stack   =   stack;                        
  return   true;  
  }  
   
  /*  
  功能:释放栈的内存  
  返回:void  
  */  
  void   free_stack()  
  {  
  free(stack);  
  stack   =   NULL;  
  }  
   
  /*  
  功能:判断栈是否已满  
  返回:true   or   false  
  */  
  bool   full()  
  {  
  return   (p_stack-stack)>=stack_size;  
  }  
   
  /*  
  功能:判断栈是否为空  
  返回:true   or   false  
  */  
  bool   empty()  
  {  
  return   (p_stack==stack);  
  }  
   
  /*  
  功能:入栈  
  返回:true   or   false  
  */  
  bool   push(NODE   p)  
  {  
  if   (!full())  
  {  
  *p_stack=p;  
  p_stack++;  
  return   true;  
  }  
  else  
  {  
  printf("stack   is   overflow   !\n");  
  return   false;  
  }  
  }  
   
  /*  
  功能:出栈  
  返回:出栈元素  
  */  
  NODE   pop()  
  {  
  if   (!empty())  
  {  
  return   *(--p_stack);  
  }  
  else  
  {  
  printf("stack   is   empty   !\n");  
  }  
  }  
   
   
   
  /*  
  功能:用栈改递归为非递归,计算Ackermann函数A(n,x,y)。  
  返回:double   计算结果  
  */  
  double   Ackermann(NODE   node)  
  {  
  double   B;  
  NODE   tnode;  
   
  if   (!full())  
  {  
  push(node);  
  }  
   
  while   (!empty())  
  {  
  tnode   =   pop();  
  while   (tnode.n   !=   0   &&   tnode.y   !=   0) /*递推,将计算参数进栈*/  
  {  
  /*修改栈顶节点的字段值,如果不好理解的话,可以参考上面的图示*/  
  (*p_stack).n--;  
  (*p_stack).y   =   (*p_stack).x;  
  (*p_stack).x   =   -1.0; /*表示x值不确定*/  
   
  /*新求得的节点值进栈*/  
  tnode.y   -=   1.0;  
  if   (!push(tnode)) /*将下一步进栈*/  
  {  
  return   -1.0;  
  }  
  }  
   
  if   (!empty())  
  {  
  tnode   =   pop();  
  }  
  if   (tnode.n   ==   0)  
  {  
  B   =   tnode.x   +   1.0;  
  }  
  else   if   (tnode.n   ==   1)  
  {  
  B   =   tnode.x;  
  }  
  else   if   (tnode.n   ==   2)  
  {  
  B   =   0.0;  
  }  
  else   if   (tnode.n   ==   3)  
  {  
  B   =     1.0;  
  }  
  else  
  {  
  B   =   2.0;  
  }  
   
  if   (!empty())  
  {  
  (*p_stack).x   =   B; /*栈不为空,则栈顶节点的x值改为B*/  
  }  
  }  
  return   B;  
  }  
   
   
  void   main(void)  
  {  
  int   i;  
  NODE   node1   =   {3,2,1},   node2   =   {4,1,2},   node3;  
  bool   success=init_stack(2);  
  if   (!success)  
  {  
  exit(0);  
  }  
   
  printf("Ackermann(%d,%d,%d)   =   %.2f\n",node1.n,(int)node1.x,(int)node1.y,Ackermann(node1));  
   
  /*  
  push(node1);  
  push(node2);  
  printf("n=%d,   x=%8f,   y=%8f\n",(*p_stack).n,(*p_stack).x,(*p_stack).y);  
  node3   =   pop();  
  printf("n=%d,   x=%8f,   y=%8f\n",(*p_stack).n,(*p_stack).x,(*p_stack).y);  
  printf("n=%d,   x=%8f,   y=%8f\n",node3.n,node3.x,node3.y);  
  */  
   
  free_stack(); /*注意程序退出时释放栈内存*/  
   
  printf("\n");  
  system("pause");  
  } 问题点数:0、回复次数:10Top

1 楼rerli(Brooks)回复于 2003-12-02 15:05:38 得分 0

/*图片乱了整理如下:  
        栈空   出栈前                     出栈后  
    |           |                     |           |                       |           |  
    |_____|p_stack-->|_____|                       |_____|  
    |_____|                     |__1__|   p_stack-->|__1__|  
  p_stack-->|_____|                     |__0__|                       |__0__|  
   
  从上图可知出栈后,栈顶指针指向的是刚才出栈元素的首地址。  
  若POP()栈顶值,此时的*p_stack和刚才pop()出来的值一模一样。  
   
  */Top

2 楼wildhorseych()回复于 2003-12-03 11:54:25 得分 0

在一般应用中,什么情况下需要用到栈?Top

3 楼ZhangYv(迎着朝阳,走向地狱)回复于 2003-12-03 12:24:53 得分 0

具备先进后出特性的任何信息都可以使用栈来表述Top

4 楼rerli(Brooks)回复于 2003-12-03 17:35:23 得分 0

 
  谢谢楼上两位的支持!  
  ZhangYv(永不放弃)   说得很对!具备先进后出特性的任何信息都可以使用栈来表述。  
  但是不同的栈有不同的用途:  
  看看我的修改稿:  
  /*  
  ==========================================  
  作者:rerli  
  时间:2003-12-03  
  目的:由一个例子学习栈。  
   
  栈应用详解:  
   
  栈的实现可以用数组,亦可用链表。  
  下面讲讲这两种实现栈结构的详细程序,并分别看看:  
  用栈改递归为非递归,计算Ackermann函数A(n,x,y)。  
  ===========================================  
  */  
   
  /*  
  ===========================================  
  第一种:数组  
  可以看出,下面的程序并没有真正用数组去实现,  
  而是使用指针。使用指针操作起来比数组稍微灵活  
  一点。下面的实现你将体会到。  
   
  栈底就是初始化后stack的首地址;  
  栈顶就是最后一个入栈元素的尾地址。  
  栈顶指针就是地址指针。  
  ===========================================  
  */  
   
   
  #include   <stdlib.h>  
  #include   <stdio.h>  
  #define   NULL   0  
   
  typedef   struct   node  
  {  
  int   n;  
  double   x;  
  double   y;  
  }NODE;  
   
  #define   LEN   sizeof(NODE)  
   
  /*栈的需要变量*/  
  typedef   enum   {false,true}bool; /*定义bool类型*/  
  static   NODE   *p_stack=NULL; /*定义栈指针变量*/  
  static   NODE   *stack=NULL; /*定义一个栈*/  
  static   unsigned   int   stack_size=0; /*栈的大小*/  
   
  /*  
  =========================================================  
      栈空  
  |           |  
  |_____|  
  |_____|  
  |_____|  
      NUll <---p_stack  
   
    出栈前  
  |           |  
  |_____|<---p_stack  
  |__1__|  
  |__0__|  
   
    出栈后  
  |           |  
  |_____|  
  |__1__|<---p_stack  
  |__0__|  
   
  从上图可知:  
  1、出栈前,栈顶指针没有指向任何元素;  
  2、出栈后,栈顶指针指向的是刚才出栈元素的首地址。  
  3、这种数组(或指针)栈描述显然有点不符合栈的定义,即栈顶指针并不是真正意义的指向栈顶(有点难懂,但从图中可以很快悟出)。  
  4、显然若我们用Pop()栈顶值后,用*p_stack取值,则必然得到Pop()出来的值一模一样。  
  ==========================================================  
  */  
   
   
  /*  
  ========================  
  功能:初始化栈的大小  
  返回:true   or   false  
  ========================  
  */  
  bool   InitStack(unsigned   int   size)  
  {  
  stack=(NODE   *)malloc(size*LEN); /*开辟空间*/                
  if   (stack==NULL) /*开辟空间失败,则返回false*/  
  {  
  return   false;  
  }  
  stack_size   =   size; /*保存栈空间大小值*/  
  p_stack   =   stack; /*栈顶指针赋初值*/          
  return   true; /*初始化成功,返回true*/  
  }  
   
  /*  
  ======================  
  功能:释放栈的内存  
  返回:void  
  ======================  
  */  
  void   FreeStack()  
  {  
  free(stack);  
  /*  
      注意:这一点很重要。free()之后并不能将stack  
      置为NULL,所以我们一定要自己做。这样能防止产生  
      “野指针”,即地址不确定的指针。  
  */  
  stack   =   NULL;  
  }  
   
  /*  
  ==========================  
  功能:判断栈是否已满  
  返回:true   or   false  
  ==========================  
  */  
  bool   Full()  
  {  
  /*栈顶指针与栈的初始地址的差,如果大于等于空间值,则此时栈满*/  
  return   (p_stack-stack)>=stack_size;  
  }  
   
  /*  
  ===========================  
  功能:判断栈是否为空  
  返回:true   or   false  
  ===========================  
  */  
  bool   Empty()  
  {  
  /*栈顶指针与栈的初始地址的相等,则栈空*/  
  return   (p_stack==stack);  
  }  
   
  /*  
  ========================  
  功能:入栈  
  返回:true   or   false  
  ========================  
  */  
  bool   Push(NODE   p)  
  {  
  if   (!Full()) /*栈不满,则入栈;栈顶指针要上移*/  
  {  
  *p_stack   =   p;  
  p_stack++;  
  return   true;  
  }  
  else  
  {  
  printf("stack   is   overflow   !\n");  
  return   false;  
  }  
  }  
   
  /*  
  ===================  
  功能:出栈  
  返回:出栈元素  
  ===================  
  */  
  NODE   Pop()  
  {  
  if   (!Empty()) /*栈不空,则出栈;栈顶指针要下移*/  
  {  
  return   *(--p_stack);  
  }  
  else  
  {  
  printf("stack   is   empty   !\n");  
  }  
  }  
   
   
   
  /*  
  ===================================================  
  功能:用栈改递归为非递归,计算Ackermann函数A(n,x,y)。  
  返回:double   计算结果  
  ===================================================  
  */  
  double   Ackermann(NODE   node)  
  {  
  double   B;  
  NODE   tnode;  
   
  if   (!Full())  
  {  
  Push(node);  
  }  
   
  while   (!Empty())  
  {  
  tnode   =   Pop();  
  while   (tnode.n   !=   0   &&   tnode.y   !=   0) /*递推,将计算参数进栈*/  
  {  
  /*修改栈顶节点的字段值,如果不好理解的话,可以参考上面的图示*/  
  p_stack->n--;  
  p_stack->y   =   p_stack->x;  
  p_stack->x   =   -1.0; /*表示x值不确定*/  
   
  /*新求得的节点值进栈*/  
  tnode.y   -=   1.0;  
  if   (!Push(tnode)) /*将下一步进栈*/  
  {  
  return   -1.0;  
  }  
  }  
   
  if   (!Empty())  
  {  
  tnode   =   Pop();  
  }  
  if   (tnode.n   ==   0)  
  {  
  B   =   tnode.x   +   1.0;  
  }  
  else   if   (tnode.n   ==   1)  
  {  
  B   =   tnode.x;  
  }  
  else   if   (tnode.n   ==   2)  
  {  
  B   =   0.0;  
  }  
  else   if   (tnode.n   ==   3)  
  {  
  B   =     1.0;  
  }  
  else  
  {  
  B   =   2.0;  
  }  
   
  if   (!Empty())  
  {  
  p_stack->x   =   B; /*栈不为空,则栈顶节点的x值改为B*/  
  }  
  }  
  return   B;  
  }  
   
   
  void   main(void)  
  {  
  NODE   node1   =   {3,1,2};  
   
  if   (!InitStack(50)) /*初始化不成功,则退出*/  
  {  
  exit(0);  
  }  
   
  printf("Ackermann(%d,%d,%d)   =   %.2f\n",node1.n,(int)node1.x,(int)node1.y,Ackermann(node1));  
   
  FreeStack(); /*注意程序退出时释放栈内存*/  
   
  printf("\n");  
  system("pause");  
  }  
  Top

5 楼rerli(Brooks)回复于 2003-12-03 17:36:29 得分 0

/*  
  =================================================================  
  作者:rerli  
  时间:2003-12-03  
  目的:由一个例子学习栈。  
   
  栈应用详解:  
   
  栈的实现可以用数组,亦可用链表。  
  下面讲讲这两种实现栈结构的详细程序,并分别看看:  
  用栈改递归为非递归,计算Ackermann函数A(n,x,y)。  
  ==================================================================  
  */  
   
  /*  
  ==================================================================  
  第二种:链表  
  用链表实现的栈称为链接栈。很显然链接栈没有栈满之说了,它是来者不拒啊!  
  栈顶是链表的第一个元素;  
  栈底是链表的最后一个元素;  
  链表的头指针就是栈顶指针。  
  ===================================================================  
  */  
   
  #include   <stdlib.h>  
  #include   <stdio.h>  
  #define   NULL   0  
   
  typedef   struct   node  
  {  
  int   n;  
  double   x;  
  double   y;  
  }NODE;  
   
  typedef   struct   lnode  
  {  
  NODE   data;  
  struct   lnode   *next;  
  }LNODE;  
   
  #define   LEN   sizeof(LNODE)  
   
  /*栈的需要变量*/  
  typedef   enum   {false,true}bool; /*定义bool类型*/  
  static   LNODE   *p_stack=NULL; /*定义栈指针变量*/  
   
  /*  
  ==================================================================  
      栈空  
  |           |  
  |_____|  
  |_____|  
  |_____|  
      NUll <---p_stack  
   
    出栈前  
  |           |  
  |_____|  
  |__1__|<---p_stack  
  |__0__|  
   
    出栈后  
  |           |  
  |_____|  
  |__1__|  
  |__0__|<---p_stack  
   
  从上图可知:  
  1、出栈前,栈顶指针指向的是栈顶元素的地址;  
  2、出栈后,栈顶指针指向的是原栈顶元素下一个元素的地址。  
  3、这种链接栈显然更符合栈的定义。相比之下,它比数组(或指针)更容易理解一些。  
  4、显然若我们用POP()栈顶值后,用*p_stack取值,则得到值不和pop()出来的值一模一样。  
  5、注意到上面的4和前面数组(或指针)栈的4有很大的差别就是根据栈顶指针取出来的值不同,  
  这样导致我们可以用数组(或指针)栈可以方便实现求Ackermann函数A(n,x,y),而链接栈则  
  不能实现,除非我们改结构。  
  ======================================================================  
  */  
   
  /*  
  ======================================================================  
  注意到链接栈比数组(或指针)栈少了几个函数,上面的变量也少了。  
  ======================================================================  
  */  
   
  /*  
  ==============================  
  功能:判断栈是否为空  
  返回:true   or   false  
  ==============================  
  */  
  bool   Empty()  
  {  
  /*栈顶指针等于NULL,则栈空*/  
  return   (p_stack==NULL);  
  }  
   
  /*  
  ==============================  
  功能:入栈  
  返回:true   or   false  
  ==============================  
  */  
  bool   Push(NODE   p)  
  {  
  static   LNODE   *stack=NULL;  
  stack   =   (LNODE   *)malloc(LEN); /*开辟一个节点的空间*/  
   
  if   (stack   !=   NULL)  
  {  
  stack->data   =   p; /*入栈*/  
  stack->next   =   p_stack; /*新节点的next指向原栈顶*/  
  p_stack   =   stack; /*栈顶指针指向新节点*/  
   
  free(stack); /*释放栈的内存*/  
  stack   =   NULL;  
  return   true;  
  }  
  else  
  {  
  return   false;  
  }  
  }  
   
  /*  
  ==============================  
  功能:出栈  
  返回:出栈元素  
  ==============================  
  */  
  NODE   Pop()  
  {  
  NODE   p;  
   
  if   (!Empty())  
  {  
  p   =   p_stack->data; /*出栈元素*/  
  p_stack   =   p_stack->next; /*更改栈顶指针*/  
  return   p;  
  }  
  else  
  {  
  printf("stack   is   empty   !\n");  
  }  
  }  
   
   
  void   main(void)  
  {  
  NODE   node1   =   {3,1,2};  
   
  Push(node1);  
  printf("n=%d,   x=%.2f,   y=%.2f\n",(p_stack->data).n,(p_stack->data).x,(p_stack->data).y);  
   
  Pop();  
  /*根据下面的语句结果,我们可以判断以上实现的栈是否正确的:1正确,其他错误。*/  
  printf("%d",p_stack==NULL);  
   
  printf("\n");  
  system("pause");  
  }Top

6 楼boy8765()回复于 2003-12-03 18:30:02 得分 0

好Top

7 楼fmonkey()回复于 2003-12-03 18:35:57 得分 0

好    
  希望以后能看到更多这样的文章  
  谢谢搂主Top

8 楼rerli(Brooks)回复于 2003-12-04 11:59:52 得分 0

谢谢鼓励!Top

9 楼chaonet(我是菜鸟)回复于 2003-12-04 13:18:26 得分 0

up   up   upTop

10 楼tass(怪物猪)回复于 2003-12-08 14:19:26 得分 0

upTop

相关问题

  • 跪求j2sdk安装与应用详解!
  • tcp/ip详解卷1中的例子怎么用啊?
  • 为何《TCP/IP详解 I》里面的例子不能编译?
  • 那里有toolbar应用的例子
  • TXMLDocument如何应用?举个例子吧?
  • CFontDialog这个类的应用例子。。。。
  • 谁有《J2EE应用开发详解》的电子版?
  • 求《JSP 应用开发详解(第二版)》电子书!!!!!!!!!!!!!!!
  • 谁能告诉我flush()的用法详解,最好能举个例子!
  • 谁有VC++中应用ODBC API 连接数据库的例子?

关键词

  • 指针
  • 节点
  • 函数
  • 学习
  • 应用
  • tnode
  • stack
  • ackermann
  • node
  • 入栈

得分解答快速导航

  • 帖主:rerli

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo