二元樹的走訪 (Binary Tree Travel), 最簡單的說法就是 “拜訪樹中所有的節點各一次”, 並且在走訪後, 將樹中的資料轉化成線性關係. 其實二元樹的走訪, 並不像之前所提到的線性資料結構般單純, 就一個簡單按二元樹節點而言, 每個節點都可以區分成左右兩個分支, 請參考下面圖形, 所以共可以有 ABC, ACB, BAC etc 等6種走訪方式. 如果是依照二元樹特性, 一律由左向右, 那只會剩下三種走訪方式, 分別是 BAC, ABC, BCA 三種 :
我們通常把這三種方式的命名與規則如下 :
對於這三種走訪方式, 只需要記得樹根的位置就不會前中後序搞混. 例如中序法即樹根在中間, 前序法則是樹根在前面以此類推. 接著以底下的二元樹為範例針對這三種走訪方式作介紹.
中序走訪 :
中序走訪的順序為 : 左子樹 > 樹根 > 右子樹
就是延著二元樹的左子樹一直往下, 直到無法前進後退回父節點, 再往右節點一直往下, 如果右子樹也走完就退回上層的左節點, 再重複左> 中 > 右的順序走訪. 以上面二元樹為例的中序走訪為 : D > B > E > A > C > F. 中序走訪的遞迴演算法如下 :
- void Inorder (btree ptr) {
- if(ptr!= NULL) {
- Inorder(ptr->left); /*走訪左子樹*/
- cout << ptr->data; /*走訪列印樹根*/
- Inorder(ptr->right); /*走訪右子樹*/
- }
- }
前序走訪 :
前序走訪的順序為 : 樹根 > 左子樹 > 右子樹
前序走訪就是從根節點開始處理, 根節點處理完後往左子樹走, 直到無法前進再處理右子樹. 以上面二元樹為例的前序走訪為 : A > B > D > E > C >F. 前序走訪的遞迴演算法如下 :
- void Inorder (btree ptr) {
- if(ptr!= NULL) {
- cout << ptr->data; /*走訪列印樹根*/
- Inorder(ptr->left); /*走訪左子樹*/
- Inorder(ptr->right); /*走訪右子樹*/
- }
- }
後序走訪 :
後序走訪的順序為 : 左子樹 > 右子樹 > 樹根
後序走訪和前序走訪的方法相反, 它是先把左子樹和右子樹的節點處理完後才處理樹根. 以上面二元樹為例的後序走訪為 : D > E > B > F > C >A. 後序走訪的遞迴演算法如下 :
- void Inorder (btree ptr) {
- if(ptr!= NULL) {
- Inorder(ptr->left); /*走訪左子樹*/
- Inorder(ptr->right); /*走訪右子樹*/
- cout << ptr->data; /*走訪列印樹根*/
- }
- }
決定為一二元樹 :
在二元樹的三種走法中, 如果有中序與前序的走訪結果或中序與後序的走訪結果, 就可以藉由這些結果求得唯一的二元樹. 不過如果只具備前序與後序的走訪結果並無法決定唯一的二元樹. 請參考下面範例 :
範例一 :
考慮我們有一二元樹, 中序走訪為 : BAEDGF, 前序走訪為ABDEFG, 請畫出此唯一二元樹 :
範例代碼 :
* LSBinaryTree.h 代碼 :
- #include
- using namespace std;
- class LSBinaryTreeNode{
- public:
- int data;
- class LSBinaryTreeNode *left;
- class LSBinaryTreeNode *right;
- LSBinaryTreeNode(){
- data = -1;
- left = NULL;
- right = NULL;
- }
- };
- typedef class LSBinaryTreeNode lsbtNode;
- typedef lsbtNode *lsbtNodePoint;
- class LSBinaryTree{
- lsbtNodePoint rootNode;
- public:
- LSBinaryTree(){
- rootNode = NULL;
- }
- virtual void add_Node_To_Tree(int value);
- virtual void inorder(); /*中序走訪二元樹*/
- virtual void preorder(); /*前序走訪二元樹*/
- virtual void postorder(); /*後序走訪二元樹*/
- protected:
- virtual void _inorder(lsbtNodePoint p);
- virtual void _preorder(lsbtNodePoint p);
- virtual void _postorder(lsbtNodePoint p);
- };
- #include "LSBinaryTree.h"
- void LSBinaryTree::add_Node_To_Tree(int value) {
- lsbtNodePoint currentNode;
- lsbtNodePoint newnode;
- int flag=0; // 用來紀錄是否插入新的節點
- newnode = (lsbtNodePoint)malloc(sizeof(lsbtNode));
- newnode->data = value;
- newnode->left = NULL;
- newnode->right = NULL;
- if(this->rootNode == NULL){
- rootNode = newnode;
- } else {
- currentNode = this->rootNode;
- while(!flag) {
- if(value<=currentNode->data) { // 往左子樹
- if(currentNode->left == NULL) {
- currentNode->left = newnode;
- flag = 1;
- } else {
- currentNode = currentNode->left;
- }
- } else { // 往右子樹
- if(currentNode->right == NULL){
- currentNode->right = newnode;
- flag = 1;
- } else {
- currentNode = currentNode->right;
- }
- }
- }
- }
- }
- void LSBinaryTree::inorder() {
- this->_inorder(this->rootNode);
- }
- void LSBinaryTree::_inorder(lsbtNodePoint p){
- if(p != NULL) {
- if(p->left != NULL)
- this->_inorder(p->left);
- cout << "[" << p->data << "] ";
- if(p->right != NULL)
- this->_inorder(p->right);
- }
- }
- void LSBinaryTree::preorder() {
- this->_preorder(this->rootNode);
- }
- void LSBinaryTree::_preorder(lsbtNodePoint p) {
- if(p!=NULL) {
- cout << "[" << p->data << "] ";
- if(p->left!=NULL)
- _preorder(p->left);
- if(p->right!=NULL)
- _preorder(p->right);
- }
- }
- void LSBinaryTree::postorder() {
- this->_postorder(this->rootNode);
- }
- void LSBinaryTree::_postorder(lsbtNodePoint p){
- if(p!=NULL){
- if(p->left!=NULL)
- _postorder(p->left);
- if(p->right!=NULL)
- _postorder(p->right);
- cout << "[" << p->data << "] ";
- }
- }
- void ch06_03(bool b) {
- if(b) {
- int value=0;
- LSBinaryTree btree;
- while(true) {
- cout << "請輸入節點值(輸入-1離開): ";
- cin >> value;
- if(value == -1)
- break;
- else
- btree.add_Node_To_Tree(value);
- }
- cout << "中序走訪: ";
- btree.inorder();
- cout << endl;
- cout << "前序走訪: ";
- btree.preorder();
- cout << endl;
- cout << "後序走訪: ";
- btree.postorder();
- cout << endl;
- }
- }
執行結果 :
補充說明 :
* [ 資料結構 小學堂 ] 樹狀結構導論 : 二元樹的儲存方式
沒有留言:
張貼留言