非递归遍历
非递归遍历要用到栈
前序
根结点-左孩子-右孩子
//前序遍历的非递归算法
void preorder(bitree *t){
bitree *temp = t;//定义一个树节点,用它来遍历
while(temp != NULL || s.top != 0) {
//先遍历左孩子,并输出。
while(temp != NULL) {
printf("%4d",temp->data);
push(temp);
temp = temp->lchild;
}
//当左孩子遍历完后,取栈顶,找右孩子。此时循环还没有结束,再遍历它的左孩子,直至孩子全部遍历结束。
if(s.top != 0) {
temp = pop();
temp = temp->rchild;
}
}
printf("\n");
}
中序
左孩子-根结点-右孩子
//中序遍历的非递归算法
void midOrder(bitree *t) {
bitree *temp = t;
while(temp != NULL||s.top != 0) {
//先把左孩子入栈,所有左孩子入栈结束
while(temp != NULL) {
push(temp);
temp = temp->lchild;
}
//左孩子入栈结束,取栈顶,输出栈顶元素,遍历右孩子
if(s.top != 0) {
temp = pop();
printf("%4d",temp->data);
temp = temp->rchild;
}
}
printf("\n");
}
后序
左孩子-右孩子-根节点
具体算法:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
//后序遍历的非递归算法
void laorder(bitree *root) {
bitree *temp = root;
while(temp!=NULL||s.top!=0) {
while(temp!= NULL) {
// 当前节点首次被访问
temp->cishu=1;
push(temp);
temp=temp->lchild;
}
if(s.top!=0) {
temp=pop( );
// 第一次出现在栈顶
if(temp->cishu == 1) {
temp->cishu++;
push(temp);
temp=temp->rchild;
} else {
//第二次输出并制空,防止陷入死循环
if(temp->cishu==2) {
printf("%4d",temp->data);
temp=NULL;
}
}
}
}
printf("\n");
}
层序遍历
层序遍历要用到队列,队列具有先进先出特性。
实现逻辑:层序遍历的思路是,创建一个队列,先将根节点(A)入队,然后用front指针将根节点记下来,再将根节点出队,接下来看front节点(也就是刚才的根节点)有没有左孩子或右孩子,如果有,先左(B)后右(C)入队,最后输出front节点的值,只要队列还不为空,就说明还没有遍历完,就进行下一次循环,这时的队头元素(front)则为刚才入队的左孩子(B),然后front出队,再把它的左右孩子拉进来(如果有),因为队列的先进先出性质,B的左右孩子DE是排在C后面的,然后输出B,下一次循环将会拉人C的左右孩子FG,最后因为FG没有左右孩子,一直出队,没有入队元素,队列迟早会变为空,当队列为空时,整颗树就层序遍历完成了,结束循环。
void LevelOrder(TreeNode *T) {
Queue<TreeNode *> q;
TreeNode *front;
if (T == NULL)return;
q.push(T);
while (!q.empty()) {
front = q.front();
q.pop();
if (front->left) {
q.push(front->left);
}
if (front->right) {
q.push(front->right);
}
printf("%c ", front->data);
}
}