|
采用链栈来递归消除二叉树的先根遍历,我遇到了一点问题。
主要的算法还是比较传统:
1.构造一个链栈
2.while(当前树结点不为NULL)
{
访问当前结点
如果存在右子树,则将右子树结点指针入栈
如果左子树为NULL时,出栈,然后将出栈的结点指针替换为当前指针,继续下一个循环
替换当前树结点为其左子树
}
按这个算法来编写C代码,没有问题,但这个栈链究竟如何能弹出结点指针呢?换句话说,如何能改变传递给出栈函数的当前结点这个参数呢?
给出完整代码,大家帮我看看。
stack.h
- #include <stdlib.h>
- /* Store per pointer of bitree */
- typedef void * lkstack_datatype;
- typedef struct lkstack_node * lkstack_pointer;
- struct lkstack_node
- {
- lkstack_datatype data;
- lkstack_pointer next;
- };
- typedef struct
- {
- lkstack_pointer top;
- } lkstack;
- /* functions for lkstack */
- int push_lkstack(lkstack *ls,lkstack_datatype x)
- {
- lkstack_pointer p=malloc(sizeof(lkstack_pointer));
- p->data=x;
- p->next=ls->top;
- ls->top=p;
- return 1;
- }
- [color=red]int pop_lkstack(lkstack *ls, lkstack_datatype *x)
- {
- lkstack_pointer p;
- if(ls->top==NULL) return 0;
- p=ls->top;
- x=p->data;
- /* DEBUG start */
- printf("*in stack* DEBUG -- %d\n",p->data);
- printf("*in stack* DEBUG -- %c\n",*x);
- /* DEBUG end */
- ls->top=p->next;
- free(p);
- return 1;
- }[/color]
- void init_lkstack(lkstack *ls)
- {
- ls->top=NULL;
- }
复制代码
bitree.c
- #include <stdlib.h>
- #ifndef RECURSION
- #include "stack.h"
- #endif
- typedef int datatype;
- typedef struct node *pointer;
- struct node
- {
- datatype data;
- pointer lchild,rchild;
- };
- typedef pointer bitree;
- bitree create_bitree (char Pre[],int ps,int pe,char In[],int is,int ie)
- {
- bitree t;
- int i;
- if(ps>pe) return NULL;
- t=(bitree *)malloc(sizeof(bitree));
- t->data=Pre[ps];
- i=is;
- while(In[i]!=Pre[ps]) i++;
- t->lchild=create_bitree(Pre,ps+1,ps+i-is,In,is,i-1);
- t->rchild=create_bitree(Pre,ps+i-is+1,pe,In,i+1,ie);
- return t;
- }
- int free_bitree(bitree t)
- {
- if(t->lchild==NULL && t->rchild==NULL) {
- free(t);
- return 1;
- }
- free_bitree(t->lchild);
- free_bitree(t->rchild);
- free(t);
- return 1;
- }
- #ifdef RECURSION
- void list_bitree_rlr(bitree t)
- {
- if(t==NULL) {
- printf("There is no data in this tree.\n");
- return 0;
- }
- if(t->lchild==NULL && t->rchild==NULL) {
- printf("%c ",t->data);
- return;
- }
- printf("%c ",t->data);
- list_bitree_rlr(t->lchild);
- list_bitree_rlr(t->rchild);
- }
- #else
- void list_bitree_rlr(bitree t)
- {
- lkstack mylkstack;
- /* DEBUG start */
- lkstack *debug=&mylkstack;
- /* DEBUG end */
- init_lkstack(&mylkstack);
- pointer p=t;
- while(p!=NULL){
- printf("%c ",p->data);
- if(p->rchild!=NULL) {
- push_lkstack(&mylkstack,p->rchild);
- /* DEBUG start */
- if (debug->top==NULL) printf("empty error.\n");
- printf("DEBUG tree -- %d\n",p->rchild);
- printf("DEBUG stack -- %d\n",debug->top->data);
- pop_lkstack(&mylkstack,p);
- printf("DEBUG pop node -- %d\n",p);
- return;
- /* DEBUG end */
- }
- if(p->lchild==NULL) {
- pop_lkstack(&mylkstack,p);
- continue;
- }
- p=p->lchild;
- }
- }
- #endif
- main()
- {
- bitree t;
- char Pre[6]="ABDEC";
- char In[6]="DBEAC";
- t=create_bitree(Pre,0,4,In,0,4);
- list_bitree_rlr(t);
- if(free_bitree(t)) printf("ok, the tree is free.\n");
- }
复制代码
运行调试:
- ibox@ibox ibox $ gcc -DRECURSION bitree.c
- bitree.c: In function `create_bitree':
- bitree.c:20: warning: assignment from incompatible pointer type
- bitree.c: In function `list_bitree_rlr':
- bitree.c:47: warning: `return' with a value, in function returning void
- ibox@ibox ibox $ ./a.out
- A B D E C ok, the tree is free.
- ibox@ibox ibox $ gcc bitree.c
- bitree.c: In function `create_bitree':
- bitree.c:20: warning: assignment from incompatible pointer type
- bitree.c: In function `list_bitree_rlr':
- bitree.c:76: warning: passing arg 2 of `pop_lkstack' from incompatible pointer type
- bitree.c:82: warning: passing arg 2 of `pop_lkstack' from incompatible pointer type
- ibox@ibox ibox $ ./a.out
- A DEBUG tree -- 134520976
- DEBUG stack -- 134520976
- *in stack* DEBUG -- 134520976
- *in stack* DEBUG -- C
- DEBUG pop node -- 134520912
- ok, the tree is free.
复制代码
1.关键在于pop_lkstack这个函数不能把弹出的结点指针传递出去,导致死循环。
2.如果采用递归方式来遍历树,倒是没有问题的。
3.如果采用顺序栈,也不会出现问题。
ps:构造树的算法是采用先根遍历和中根遍历序列结合生成的
所以,整个算法是正确的,但错就错在C语言本身的指针规范,我不太清楚,大家指点。尤其是kj501兄,帮帮忙,谢谢。 |
|