/*
==========================================
作者: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");
}
本文地址:http://com.8s8s.com/it/it29032.htm