遍历二叉树的各种实现

以下程序测试使用的二叉树:

 

前序遍历序列:1 2 3 6 8 9 7

中序遍历序列:2 1 6 9 8 3 7

后序遍历序列:2 9 8 6 7 3 1

层序遍历序列:1 2 3 6 7 8 9

 

二叉树类型定义和访问函数

 typedef struct Node { int data; struct Node* lChild; struct Node* rChild; }BiNode, *BiTree; void Visit(BiNode* node) { printf("%d ", node->data); }

 

【1. 前序遍历-递归】

也可以叫深度遍历,先访问根节点,再依次访问其左、右子树。

//前序遍历,递归(深度遍历) void PreOrderTraverse(BiTree root) { if (root == NULL) return; Visit(root); PreOrderTraverse(root->lChild); PreOrderTraverse(root->rChild); } //前序遍历,递归,减少递归次数。 void PreOrderTraverse_2(BiTree root) { if (root == NULL) return; Visit(root); if (root->lChild) //减少递归次数 PreOrderTraverse(root->lChild); if (root->rChild) PreOrderTraverse(root->rChild); }

 

【2.1 前序遍历-非递归】

 

需要用到栈。根节点先入栈,当栈不为空循环,依次取出栈顶结点,访问,将其右、左子树依次入栈。注意要先将右子树入栈,后将左子树入栈,这样在出栈时,先访问左边。

 //前序遍历,非递归 void PreOrderTraverse_Loop(BiTree root) { if (root == NULL) return; BiNode* node = NULL; stack<BiNode*> biStack; biStack.push(root); while(!biStack.empty()) { node = biStack.top(); biStack.pop(); Visit(node); if (node->rChild)//右子树先入栈 biStack.push(node->rChild); if (node->lChild) biStack.push(node->lChild); } }

 

 【2.2 前序遍历-非递归】

 

先将根节点入栈,如果栈不为空,循环:向左走到头,沿途访问结点并入栈,直到最左结点,出栈一个结点,将其右子树入栈。

 //前序遍历,非递归 void PreOrderTraverse_Loop_2(BiTree root) { if (root == NULL) return; BiNode* node = NULL; stack<BiNode*> biStack; biStack.push(root); while(!biStack.empty()) { node = biStack.top(); while (node) //向左走到头 { Visit(node); biStack.push(node->lChild); node = node->lChild; } biStack.pop(); // 栈顶NULL出栈 if (!biStack.empty()) { node = biStack.top(); biStack.pop(); biStack.push(node->rChild); } } }

 

【3. 中序遍历-递归】

先访问左子树,再访问根结点,最后访问右子树。

//中序遍历,递归 void InOrderTraverse(BiTree root) { if (root == NULL) return; InOrderTraverse(root->lChild); Visit(root); InOrderTraverse(root->rChild); }

 

【4.1 中序遍历-非递归】

如果结点不为空或栈不为空,循环:如果结点不为空,入栈,下一次查看其左子树(沿着左边一直往下,直到其最左结点);如果结点为空,出栈一个结点,访问此结点,下一次查看其右子树。

 

如果结点为空:

-当前结点是一个左子树结点,此NULL结点的父结点其实没有左子树,将父节点出栈,访问父节点(左子树已完成),接着查看父节点的右子树,右子树并未入栈。

-当前结点是一个右子树结点,此NULL结点的父结点其实没有右子树,此时栈顶是父节点的父节点,代表父节点为根的树遍历完成了,出栈,接着查看父节点的父节点的右子树。

//中序遍历,非递归 void InOrderTraverse_Loop_1(BiTree root) { if (root == NULL) return; stack<BiNode*> biStack; BiNode* node = root; while(node || !biStack.empty()) { if (node) { biStack.push(node); node = node->lChild; } else { node = biStack.top(); biStack.pop(); Visit(node); node = node->rChild; } } }

 

【4.2 中序遍历-非递归】

 

与【2.2 前序遍历-非递归】几乎一摸一样,除了Visit() 调用的位置。

 //中序遍历,非递归 void InOrderTraverse_Loop_2(BiTree root) { BiNode* node = NULL; stack<BiNode*> biStack; biStack.push(root); while(!biStack.empty()) { node = biStack.top(); while(node) //向左走到尽头 { biStack.push(node->lChild); node = node->lChild; } biStack.pop(); //栈顶NULL结点出栈 if (!biStack.empty()) { node = biStack.top(); biStack.pop(); Visit(node); biStack.push(node->rChild); } }//end of while }

 

【5. 后序遍历-递归】

先遍历左子树,再遍历右子树,最后访问根结点。

//后序遍历,递归 void PostOrderTraverse(BiTree root) { if (root == NULL) return; PostOrderTraverse(root->lChild); PostOrderTraverse(root->rChild); Visit(root); }

 

【5.1 后序遍历-非递归】

 

根节点入栈,如栈不为空,循环:last记住刚访问过的结点;第二个if,将树上所有的节点都按根、右、左的次序入栈;第一个if,如果是last == node->lChild,而由于入栈顺序是根右左,说明node没有右子树,接下来该访问根了;如果是last == node->rChild,说明node的左右子树都访问完了,根据后序遍历的定义,接下来该访问根了。

 //后序遍历,非递归 void PostOrderTraverse_Loop_1(BiTree root) { if (root == NULL) return; BiNode* node = NULL; BiNode* last = NULL; stack<BiNode*> biStack; biStack.push(root); while(!biStack.empty()) { node = biStack.top(); biStack.pop(); if (last == node->lChild || last == node->rChild) { //左右子树已经访问完了,该根节点了 Visit(node); last = node; } else if (node->lChild || node->rChild) { //左右子树未访问,当前结点入栈,右、左结点依次入栈 biStack.push(node); if (node->rChild) biStack.push(node->rChild); if (node->lChild) biStack.push(node->lChild); } else // 当前结点是叶子结点,访问 { Visit(node); last = node; } } }

 

【5.2 后序遍历-非递归】

这个很难理解。。。

 //后序遍历,非递归 void PostOrderTraverse_Loop_2(BiTree root) { stack<BiNode*> biStack; BiNode* pre = NULL; while (root != NULL || !biStack.empty()) { if (root != NULL) // 向左走到头 { biStack.push(root); root = root->lChild; } else { root = biStack.top(); //如果右子树还未访问过 if (root->rChild != NULL && pre != root->rChild) { root = root->rChild; } else { root = biStack.top(); biStack.pop(); Visit(root); pre = root; root = NULL; } } } } 

 

【6. 层序遍历】

也叫广度遍历,使用队列实现。

//广度遍历 void LevelOrderTraverse(BiTree root) { if (root == NULL) return; BiNode* node = NULL; queue<BiNode*> biQueue; biQueue.push(root); while(!biQueue.empty()) { node = biQueue.front(); biQueue.pop(); Visit(node); if (node->lChild) biQueue.push(node->lChild); if (node->rChild) biQueue.push(node->rChild); } }

你可能感兴趣的:(struct,测试,null)