最近一段时间学习数据结构,关于二叉树的遍历,递归遍历很简单,非递归遍历方法不一这里分析一下三种非递归遍历方法的实现
首先定义二叉树结点数据结构:
typedef struct btnode *btlink struct btnode { TreeItem element; btlink left; //左子树 btlink right; //右子树 }Btnode;
下面给出几种非递归遍历的方法:
一:非递归前序遍历:
void PreOrder(void (*visit)(btlink u),btlink t) { Stack s = StackInit(); Push(t,s); while(!StackEmpty(s)) { (*visit)(t = Pop(s)); if(t->right) Push(t->right,s); if(t->left) Push(t->left,s); }
分析代码,实现方法很简单:
1:首先将根结点压入栈中,然后根据栈是否为空来进行循环,每次访问一个结点
2:然后将其存在的左右子结点压入栈中
3:然后开始从1到3的循环
二:非递归中序遍历:
void InOrder(void (*visit)(btlink u),btlink t) { Stack s = StackInit(); btlink tmp = t; while( !StackEmpty(s)||tmp) { while(tmp->left) { Push(tmp,s); tmp = tmp->left; } if(tmp) (*visit)tmp; if(!StackEmpty(s)&&!tmp->right) { tmp = Pop(s); (*visit)tmp; } tmp = tmp->right; } }
分析代码:
1:首先利用while循环,从根结点开始,如果一个结点没有左子结点,则将这个结点压入
2:判断临时结点指针是否为空,不为空,则读取该结点
3:判断栈是否为空,不为空且临时指针右儿子结点为空,则压出一个结点,并读取
4:临时指针指向其右儿子结点
三:非递归后序遍历
void PostOrder(void (*visit)(btlink u),btlink t) { Stack s = StackInit(); btlink tmp = t; btlink tmpvisit; while( !StackEmpty(s)||tmp) { while(tmp->left) { Push(tmp,s); tmp = tmp->left; } if(tmp->right) { Push(tmp,s) tmp = tmp->right; } else { (*visit)tmp; tmpvisit = tmp; tmp = Pop(s); if(tmp->right==tmpvisit||(!tmp->right&&tmp->left==tmpvisit)) { (*visit)tmp; tmpvisit =tmp; tmp = Pop(s); } else if (tmp->right) { Push(tmp,s); tmp = tmp->right; } else { (*visit)tmp; tmpvisit = tmp; tmp = Pop(s); } } while((tmp->right==tmpvisit||(!tmp->right&&tmp->left==tmpvisit) { (*visit)tmp; tmpvisit==tmp; if(!StackEmpty(s)) { tmp = Pop(s); if(tmp==t&&tmp->right) { Push(t,s); tmp = tmp->right; } } else tmp = NULL; } } }
分析代码:虽然代码比较复杂,但总的来说是自己的一个思路,往各位指正
1:首先利用while循环,从根结点开始,倘若该结点有右子结点,则压入栈中,若没有,赋予tmp
2:分析tmp指向的结点,倘若存在右子结点,则将该结点压入栈中,tmp指向其右子结点,倘若没有,则将该结点读取,将读取的结点赋予tmpvisit。
3:然后进行出栈操作,将出栈的结点赋予tmp,对tmp进行判断,倘若该结点的右子结点已经读取或者右子结点不存在且左子结点已经读取,则读取该结点。否则判断其右子结点是否存在,存在则重复上面2的操作,不存在,则读取该结点,并压出栈,存入tmp中
4:利用对tmp进行判断,让若其右子结点已经读取或者右子结点不存在且左子结点已经读取,则读取该结点,否则不操作,同时,对栈进行空判断,而且对根结点进行右子结点判断。