由一个例子学习栈
来源:互联网 发布:相片影集制作软件 编辑:程序博客网 时间:2024/06/01 13:05
/*
==========================================
作者: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");
}
- 由一个例子学习栈
- 由一个例子学习栈(续)
- 由一个线程例子引发的思考
- C++::由一个例子入手前置声明
- 由一个简单例子上手neon
- 一个学习例子
- 由一个例子想到对事务脚本模式的问题
- 由一个例子引起的对递归原理的理解。
- 由一个线程例子引发的思考(转载)
- 一个由库表到POJO的myBatis配置文件建立的例子
- 学习JavaCC - 一个简单例子
- 学习JavaCC - 一个简单例子
- 通过一个例子学习stringstream
- 栈的一个例子
- 由最简单的一个例子说起,匿名用户可读可写的实现(LINUX)配置
- 由《C缺陷和陷阱》上的一个例子想到的
- [原创][Java]由一个Java编程思想书中线程间协作的例子想到的
- 由一个例子,介绍linux目录的多用户及其读写可执行权限
- 提醒初学者注意 send(sendto) recv(recvfrom) 中的 参数flags
- 写扫雷的一点感想(初学的朋友可以看看)
- C#实现WEB服务器
- 小写转大写金额[SQL SERVER]
- 我遇见的SQL SERVER 2000 的错误
- 由一个例子学习栈
- 由一个例子学习栈(续)
- 单向链表操作详解(一)
- 单向链表操作详解(二)[The End]
- 重温经典排序思想--C语言常用排序全解
- 简单一道排序题,考倒多少读书人!——从华为一道面试题浅谈计算机专业在校大学生该如何学习专业课程,信心百倍挑战就业!
- 学习队列
- 音量调节及静音
- 代码重构实践 —— 代码改进的一个案例分析