您的位置:首页 > 其它

利用指针传递参数

2008-11-18 14:05 190 查看
最近在给学生讲授数据结构课程的树和二叉树这一章时,调试书的的代码发现几个问题,花了不少时间才解决,感觉自己对指针这玩意的理解还有待深入。

二叉树的遍历有三种,先序、中序和后序,通常是利用递归来进行遍历。如果不利用递归,这时候就要借鉴于堆栈(Stack)这种数据结构。根据树上的定义,我们可以定义以下栈来存储树的节点:
//二叉树节点的定义
typedef struct BiNode {
TElemType data;
struct BiNode *lchild, *rchild; //左右孩子指针
}BiTNode, *BiTree;

#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量

typedef struct {
BiTNode* base; //在栈构造之前和销毁后,该指针为NULL
BiTNode* top; //栈顶指针
int stacksize; //当前已经分配的存储空间,以元素为单位
}SqStack;
这个地方的关键在于,平时我们入栈的可能是build-in type数据,如int。而这个地方我们入栈的是树的节点。其关键的Push和Pop操作,按照书上的实现如下:
Status Push(SqStack &S,BiTNode* e)
{
if(S.top - S.base >= S.stacksize) //栈满,追加存储空间
{
S.base = (BiTNode*)realloc(S.base, (S.stacksize + STACKINCREMENT)*sizeof /
(BiTNode));

if(!S.base) exit(OVERFLOW);

S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}

if(e != NULL)
{
*S.top = *e; //e的值(*e)入栈
S.top++;
}

return OK;
} //Push

/*
* 说明:该函数通过参数e将栈顶元素返回
* 但此时的e传递进来时,必须已经赋值
*/
Status Pop(SqStack &S, BiTNode* e)
{
if(S.base == S.top || !e)
{
return ERROR;
}

--S.top;
(*e) = *S.top; //弹出的值赋予给*e
//e = S.top; //error.

return OK;
}

在上面代码中,要注意的是,我们入栈的是节点包含的数据,而不是节点指针本身。在Push实现时,我就犯了以上错误,代码如下:
S.top = e; //error!
S.top++;
结果把栈顶指针给改变了。

但是上述的Pop函数在实际调用过程中也存在着很大问题,见下面代码:
//中序非递归遍历二叉树T,对每个结点调用函数Visit一次且仅一次。
Status InOrderTraverse1(BiTree T, Status(*Visit)(TElemType e)) //方法1(6.2)
{
SqStack S;
InitStack(S);

BiTNode* p = T;
while(p != NULL || !IsStackEmpty(S))
{
while(p != NULL)
{
Push(S, p);
p = p->lchild;
}

if(!IsStackEmpty(S))
{
p = (BiTNode*)malloc(sizeof(BiTNode));
Pop(S, p); //Here, the problem is how to delete p?

if(!Visit(p->data))
return ERROR;

p = p->rchild;
}
}

DestroyStack(S);
return OK;
}
见上面我的注释//Here, the problem is how to delete p? 在从栈顶取元素时,我们必须传入指针p,但是此p必须在使用前赋值,否则出错!关键是在何时delete p。想了很久,一直没有找到比较好的解决办法???

最终,采用的是另一种方法,即Pop函数实现如下:
/*
* 说明:该函数通过函数返回值将栈顶元素返回
*
*/
BiTNode* Pop(SqStack &S)
{
if(S.base == S.top)
{
return NULL;
}

--S.top;

return S.top;
}

最终,在遍历函数中调用过程如下:
//中序非递归遍历二叉树T,对每个结点调用函数Visit一次且仅一次。
Status InOrderTraverse1(BiTree T, Status(*Visit)(TElemType e)) //方法1(6.2)
{
SqStack S;
InitStack(S);

BiTNode* p = T;
while(p != NULL || !IsStackEmpty(S))
{
while(p != NULL)
{
Push(S, p);
p = p->lchild;
}

if(!IsStackEmpty(S))
{
p = Pop(S); //为什么这个调用可以!

if(!Visit(p->data))
return ERROR;

p = p->rchild;
}
}

DestroyStack(S);
return OK;
}
实际上,我们把问题丢给了编译器,因为函数的返回值是在系统Stack中分配的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: