二叉樹的詳細實現 (C++)

二叉樹的定義

    以遞歸形式給出的:一棵二叉樹是結點的一個有限集合,該集合或者爲空,或者是由一個根結點加上兩棵分別稱爲左子樹和右子樹的、互不相交的二叉樹組成。二又樹的特色是每一個結點最多有兩個子女,分別稱爲該結點的左子女和右子女。在二又樹中不存在度大於2的結點,而且二又樹的子樹有左、右之分,其子樹的次序不能顛倒。二又樹是分支數最大不超過2的有根有序樹。它可能有5種不一樣的形態。

二叉樹的性質

 

二叉樹的數組存儲方式

 

    遇到空子樹,應在編號時假定有此子樹進行編號,而在順序存儲時看成有此子樹那樣把位置留出來。這樣才能反映二叉樹結點之間的相互關係,由其存儲位置找到它的父結點、子女、兄弟結點的位置。但這樣作有可能會消耗大量的存儲空間。例如:單支二叉樹,會浪費不少空間。算法

 
若是根節點編號是從1開始有有如下結論:
    中間節點必定在倒數第二層,最後一個節點的數就是總節點的個數,總結點數除2就是中間節點的數的個數,父節點的節點數*2<總節點個數,當前節點必定有兩個孩子,若是=就只有一個孩子,若是<就沒有一個孩子。

二叉樹的鏈表存儲表示

 

二叉樹結點類型的定義

1 template<typename T>
2 struct BinTreeNode 3 { 4     T data;    //結點中存儲的數據
5     BinTreeNode<T> *leftChild, *rightChild;    //左子樹和右子樹
6     BinTreeNode() :leftChild(NULL), rightChild(NULL) {}    //無參構造函數
7     BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) :data(x), leftChild(l), rightChild(r) {}    //帶默認值的有參構造參數
8 };

二叉樹的基本框架

 

//二叉樹 //結點類型
template <typename T>
struct BinTreeNode { T data; //結點中存儲的數據
    BinTreeNode<T> *leftChild, *rightChild;                                                                        //左子樹和右子樹
    BinTreeNode() : leftChild(NULL), rightChild(NULL) {}                                                           //無參構造函數
    BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) : data(x), leftChild(l), rightChild(r) {} //帶默認值的有參構造參數
}; //二叉樹類
template <typename T>
class BinaryTree { public: //==========二叉樹構造與析構==========//

    //構造函數
 BinaryTree() : root(NULL) {} //指定結束標誌的構造函數
 BinaryTree(T value) : RefValue(value), root(NULL) {} //析構函數
    ~BinaryTree() { Destroy(root); } //==========二叉樹的建立==========//

    //使用廣義表建立二叉樹,以'#'字符表明結束
    void CreateBinTree() { CreateBinTree(root); } //前序遍歷建立二叉樹(前序遍歷的應用),用#表示空結點
    void CreateBinTree_PreOrder() { CreateBinTree_PreOrder(root); } //使用先序遍歷和中序遍歷建立二叉樹
    void CreateBinTreeBy_Pre_In(const char *pre, const char *in) { int n = strlen(pre); CreateBinTreeBy_Pre_In(root, pre, in, n); } //使用後序遍歷和中序遍歷建立二叉樹
    void CreateBinTreeBy_Post_In(const char *post, const char *in) { int n = strlen(post); CreateBinTreeBy_Post_In(root, post, in, n); } //==========二叉樹的遍歷==========//

    //先序遍歷(遞歸)
    void PreOrder() { PreOrder(root); } //中序遍歷(遞歸)
    void InOrder() { InOrder(root); } //後序遍歷(遞歸)
    void PostOrder() { PostOrder(root); } //先序遍歷(非遞歸)
    void PreOrder_NoRecurve() { PreOrder_NoRecurve(root); } //中序遍歷(非遞歸)
    void InOrder_NoRecurve() { InOrder_NoRecurve(root); } //後序遍歷(非遞歸)
    void PostOrder_NoRecurve() { PostOrder_NoRecurve(root); } //層次遍歷(非遞歸)
    void LevelOrder() { LevelOrder(root); } //==========獲取結點==========//

    //獲取二叉樹的根節點
    BinTreeNode<T> *getRoot() const { return root; } //獲取current結點的父節點
    BinTreeNode<T> *Parent(BinTreeNode<T> *current) { return (root == NULL || root == current) ? NULL : Parent(root, current); //若是沒有根節點或current結點就是root結點,就沒有父節點
 } //獲取current結點的左結點
    BinTreeNode<T> *LeftChild(BinTreeNode<T> *current) { return (current != NULL) ? current->leftChild : NULL; } //獲取current結點的右結點
    BinTreeNode<T> *RightChild(BinTreeNode<T> *current) { return (current != NULL) ? current->rightChild : NULL; } //==========成員函數==========//

    //銷燬函數
    void Destroy() { Destroy(root); } //拷貝二叉樹(前序遍歷的應用)
    BinaryTree(BinaryTree<T> &s) { root = Copy(s.getRoot()); } //判斷兩顆二叉樹是否相等(前序遍歷的應用)
    bool operator==(BinaryTree<T> &s) { return (equal(this->getRoot(), s.getRoot())); } //計算二叉樹的結點的個數(後序遍歷的應用)
    int Size() { return Size(root); } //計算二叉樹的高度(後序遍歷的應用)
    int Height() { return Height(root); } //判斷二叉樹是否爲空
    bool Empty() { return (root == NULL) ? true : false; } //以廣義表的形式輸出二叉樹(前序遍歷的應用)
    void PrintBinTree() { PrintBinTree(root); } private: BinTreeNode<T> *root; //根節點
    T RefValue;           //數據輸入中止的標誌,須要一個構造函數
};

 

二叉樹的建立

  1.使用廣義表建立

從廣義表 A(B(D,E(G,)),C(,F))# 創建起來的二叉樹。
 
算法基本思路:
  1.如果字母(假定以字母做爲結點的值),則表示是結點的值,爲它創建一個新的結點,並把該結點做爲左子女(當k=1)或右子女(當k=2)連接到其父結點上。
  2.如果左括號"(",則代表子表的開始,將k置爲1;若遇到的是右括號")",則代表子表結束。
  3.若遇到的是逗號",",則表示以左子女爲根的子樹處理完畢,應接着處理以右子女爲根的子樹,將k置爲2。如此處理每個字符,直到讀入結束符「#」爲止。
在算法中使用了一個棧s,在進入子表以前將根結點指針進棧,以便括號內的子女連接之用。在子表處理結束時退棧。
 
 1     //使用廣義表建立二叉樹函數,這裏以「字符」建立二叉樹,以'#'字符表明結束
 2     void CreateBinTree(BinTreeNode<T>* &BT)  3  {  4         stack< BinTreeNode<T>* > s;  5         BT = NULL;  6         BinTreeNode<T> *p, *t;    //p用來記住當前建立的節點,t用來記住棧頂的元素
 7         int k;    //k是處理左、右子樹的標記
 8  T ch;  9         cin >> ch; 10 
11         while (ch != RefValue) 12  { 13             switch (ch) 14  { 15             case '(':    //對(作處理
16  s.push(p); 17                 k = 1; 18                 break; 19 
20             case ')':    //對)作處理
21  s.pop(); 22                 break; 23 
24             case ',':    //對,作處理
25                 k = 2; 26                 break; 27 
28             default: 29                 p = new BinTreeNode<T>(ch);    //構造一個結點
30                 if (BT == NULL)    //若是頭節點是空
31  { 32                     BT = p; 33  } 34                 else if (k == 1)    //鏈入*t的左孩子
35  { 36                     t = s.top(); 37                     t->leftChild = p; 38  } 39                 else    //鏈入*t的右孩子
40  { 41                     t = s.top(); 42                     t->rightChild = p; 43  } 44  } 45             cin >> ch; 46  } 47     }

   2.使用已知的二叉樹的前序遍歷建立數組

  必須對應二又樹結點前序遍歷的順序,並約定以輸入序列中不可能出現的值做爲空結點的值以結束遞歸,此值經過構造函數存放在RefValue中。例如用「#」或表示字符序列或正整數序列空結點。
 
  前序遍歷所獲得的前序序列爲ABC##DE#G##F###。
算法的基本思想是:
  每讀入一個值,就爲它創建結點。該結點做爲根結點,其地址經過函數的引用型參數subTree直接連接到做爲實際參數的指針中。而後,分別對根的左、右子樹遞歸地創建子樹,直到讀入「#」創建空子樹遞歸結束。
 
 1     //建立二叉樹(利用已知的二叉樹的前序遍歷建立)用#表示空結點
 2     void CreateBinTree_PreOrder(BinTreeNode<T>* &subTree)  3  {  4  T item;  5         if (cin >> item)  6  {  7             if (item != RefValue)  8  {  9                 subTree = new BinTreeNode<T>(item);    //構造結點
10                 if (subTree == NULL) 11  { 12                     cout << "空間分配錯誤!" << endl; 13                     exit(1); 14  } 15                 CreateBinTree_PreOrder(subTree->leftChild);    //遞歸建立左子樹
16                 CreateBinTree_PreOrder(subTree->rightChild);    //遞歸建立右子樹
17  } 18             else
19  { 20                 subTree == NULL; 21  } 22  } 23     }

    3.根據已知的前序遍歷和中序遍歷建立二叉樹框架

        根據前序遍歷,先找到這棵樹的根節點,也就是數組受中第一個結點的位置,建立根節點。函數

        而後在中序遍歷中找到根的值所在的下標,切出左右子樹的前序和中序post

        注意:若是前序遍歷的數組長度爲0,說明是一棵空樹。this

舉例:spa

首先能夠肯定A是這棵樹的根節點,而後根據中序遍歷切出A的左右子樹,獲得BCD屬於A的左子樹,E屬於A的右子樹,以下圖:指針

接着以B爲根節點,在中序遍歷中再次切出B的左右子樹,獲得CD爲B的左子樹,右子樹爲空。code

再以C爲根節點,結合中序遍歷,獲得D爲C的右子樹,左子樹爲空。blog

建立好的二叉樹以下圖所示:

 

 1     //使用先序遍歷和中序遍歷建立二叉樹
 2     void CreateBinTreeBy_Pre_In(BinTreeNode<T> *&cur, const char *pre, const char *in, int n)  3  {  4         if (n <= 0)  5  {  6             cur = NULL;  7             return;  8  }  9         int k = 0; 10         while (pre[0] != in[k]) //再中序中找到pre[0]的值
11  { 12             k++; 13  } 14         cur = new BinTreeNode<T>(in[k]); //建立結點
15         CreateBinTreeBy_Pre_In(cur->leftChild, pre + 1, in, k); 16         CreateBinTreeBy_Pre_In(cur->rightChild, pre + k + 1, in + k + 1, n - k - 1); 17     }

 

    4.根據已知的後續遍歷和中序遍歷建立二叉樹

        根據後序遍歷,先找到這棵樹的根節點的值,也就是數組中最後一個節點(數組長度-1)的位置,由此建立根節點。
        而後在中序遍歷中找到根的值所在的下標,切出左右子樹的後續和中序。
        注意:若是後序遍歷的數組長度爲0,說明是一棵空樹。

舉例:

由後序遍歷能夠肯定A是這棵樹的根節點,而後根據中序遍歷切出A的左右子樹,獲得CDB屬於A的左子樹,E屬於A的右子樹,以下圖:

接着以B爲根節點,在中序遍歷中再次切出B的左右子樹,獲得CD爲B的左子樹,右子樹爲空。

再以C爲根節點,結合中序遍歷,獲得D爲C的右子樹,左子樹爲空。

建立好的二叉樹以下圖所示:

 1 //使用後序遍歷和中序遍歷建立二叉樹
 2     void CreateBinTreeBy_Post_In(BinTreeNode<T> *&cur, const char *post, const char *in, int n)  3  {  4         if (n == 0)  5  {  6             cur = NULL;  7             return;  8  }  9 
10         char r = *(post + n - 1);    //根結點值
11         cur = new BinTreeNode<T>(r); //構造當前結點
12 
13         int k = 0; 14         const char *p = in; 15         while (*p != r) 16  { 17             k++; 18             p++; 19  } 20         CreateBinTreeBy_Post_In(cur->leftChild, post, in, k); 21         CreateBinTreeBy_Post_In(cur->rightChild, post + k, p + 1, n - k - 1); 22     }

 

二叉樹的遞歸遍歷

  先序遍歷:根->左->右

 1     //二叉樹的先序遍歷
 2     void PreOrder(BinTreeNode<T> *&subTree)  3  {  4         if (subTree != NULL)  5  {  6             cout << subTree->data << " ";  7             PreOrder(subTree->leftChild);  8             PreOrder(subTree->rightChild);  9  } 10     }

  中序遍歷:左->根->右

 1     //二叉樹的中序遍歷
 2     void InOrder(BinTreeNode<T> *&subTree)  3  {  4         if (subTree != NULL)  5  {  6             InOrder(subTree->leftChild);  7             cout << subTree->data << " ";  8             InOrder(subTree->rightChild);  9  } 10     }

  後續遍歷:左->右->根

 1     //二叉樹的後序遍歷
 2     void PostOrder(BinTreeNode<T> *&subTree)  3  {  4         if (subTree != NULL)  5  {  6             PostOrder(subTree->leftChild);  7             PostOrder(subTree->rightChild);  8             cout << subTree->data << " ";  9  } 10     }

 二叉樹的非遞歸遍歷

  先序遍歷

  爲了把一個遞歸過程改成非遞歸過程,通常須要利用一個工做棧,記錄遍歷時的回退路徑。
 

  利用棧實現前序遍歷的過程。每次訪問一個結點後,在向左子樹遍歷下去以前,利用這個棧記錄該結點的右子女(若是有的話)結點的地址,以便在左子樹退回時能夠直接從棧頂取得右子樹的根結點,繼續其右子樹的前序遍歷。

 
 1     //二叉樹先序遍歷(非遞歸1)
 2     void PreOrder_NoRecurve1(BinTreeNode<T> *p)  3  {  4         stack<BinTreeNode<T>*> S;  5         S.push(NULL);    //最早push一個NULL,到最後一個結點沒有左右子樹時,棧裏只有一個NULL了,令指針p指向這個NULL,再判斷就會結束循環
 6         while (p!=NULL)  7  {  8             cout << p->data << " ";  9             if(p->rightChild!=NULL)    //預留右子樹指針在棧中
10  { 11                 S.push(p->rightChild); 12  } 13 
14             if (p->leftChild!=NULL)    //進左子樹
15  { 16                 p = p->leftChild; 17  } 18             else    //左子樹爲空
19  { 20                 p = S.top(); 21  S.pop(); 22  } 23  } 24     }

     另外一種前序遍歷的方法。爲了保證先左子樹後右子樹的順序,在進棧時是先進右子女結點地址,後進左子女結點地址,出棧時正好相反。

 1     //二叉樹先序遍歷(非遞歸2)
 2     void PreOrder_NoRecurve2(BinTreeNode<T> *p)  3  {  4         stack<BinTreeNode<T>*> S;  5         BinTreeNode<T>* t;  6         S.push(p);    //根節點進棧
 7         while (!S.empty())    //當棧不爲空
 8  {  9             t = S.top();    //p先記住棧頂元素,而後棧頂出棧
10  S.pop(); 11             cout << t->data << " ";    //訪問元素
12             if (t->rightChild != NULL)    //右孩子不爲空,右孩子近棧
13  { 14                 S.push(t->rightChild); 15  } 16             if (t->leftChild != NULL)    //左孩子不爲空,左孩子進棧
17  { 18                 S.push(t->leftChild); 19  } 20  } 21     }

   中序遍歷

  須要使用一個棧,以記錄遍歷過程當中回退的路徑。在一棵子樹中首先訪問的是中序下的第一個結點,它位於從根開始沿leftChild鏈走到最左下角的結點,該結點的leftChild指針爲NULL。訪問它的數據以後,再遍歷該結點的右子樹。此右子樹又是二叉樹,重複執行上面的過程,直到該子樹遍歷完。
 
  若是某結點的右子樹遍歷完或右子樹爲空,說明以這個結點爲根的二叉樹遍歷完,此時從棧中退出更上層的結點並訪問它,再向它的右子樹遍歷下去。
 1     //二叉樹的中序遍歷(非遞歸)
 2     void InOrder_NoRecurve(BinTreeNode<T>* p)  3  {  4         stack<BinTreeNode<T>*> S;  5         do
 6  {  7             while (p!=NULL)  8  {  9  S.push(p); 10                 p = p->leftChild; 11  } 12             if (!S.empty()) 13  { 14                 p = S.top(); 15  S.pop(); 16                 cout << p->data << " "; 17                 p = p->rightChild; 18  } 19  } 20         while (p!=NULL||!S.empty()); 21     }

  後續遍歷

思想:
一、若是棧頂元素非空且左節點存在,將其壓入棧中,若是棧頂元素存在左節點,將其左節點壓棧,重複該過程。直到左結點不存在則進入第2步
二、判斷上一次出棧節點是不是當前棧頂結點的右節點(就是右葉子結點,如:g,f結點),或者當前棧頂結點不存在右結點(如:g,f,a結點),將當前節點輸出,並出棧。不然將當前棧頂結點右孩子節點壓棧,再進入第1步
 1     //後序遍歷(非遞歸)
 2     void PostOrder_NoRecurve(BinTreeNode<T> *p)  3  {  4         if (root == NULL)  5             return;  6         stack<BinTreeNode<T> *> s;  7  s.push(p);  8         BinTreeNode<T> *lastPop = NULL;  9         while (!s.empty()) 10  { 11             while (s.top()->leftChild != NULL) 12                 s.push(s.top()->leftChild); 13             while (!s.empty()) 14  { 15                 //右葉子結點 || 沒有右結點
16                 if (lastPop == s.top()->rightChild || s.top()->rightChild == NULL) 17  { 18                     cout << s.top()->data << " "; 19                     lastPop = s.top(); 20  s.pop(); 21  } 22                 else if (s.top()->rightChild != NULL) 23  { 24                     s.push(s.top()->rightChild); 25                     break; 26  } 27  } 28  } 29     }

 

  層次遍歷

    按層次順序訪問二叉樹的處理須要利用一個隊列。在訪問二又樹的某一層結點時,把下一層結點指針預先記憶在隊列中,利用隊列安排逐層訪問的次序。所以,每當訪問一個結點時,將它的子女依次加到隊列的隊尾,而後再訪問已在隊列隊頭的結點。這樣能夠實現二又樹結點的按層訪問。
 
 1     //二叉樹的層次遍歷(非遞歸遍歷)
 2     void LevelOrder(BinTreeNode<T> *p)  3  {  4         queue<BinTreeNode<T>*> Q;  5         Q.push(p);    //根節點進隊
 6         BinTreeNode<T>* t;  7         while (!Q.empty())  8  {  9             t = Q.front();    //t先記住隊頭,再將隊頭出隊
10  Q.pop(); 11             cout << t->data << " ";    //訪問隊頭元素的數據
12 
13             if (t->leftChild != NULL) 14  { 15                 Q.push(t->leftChild); 16  } 17 
18             if (t->rightChild != NULL) 19  { 20                 Q.push(t->rightChild); 21  } 22  } 23     }

 二叉樹的結點個數

1     //計算二叉樹以subTree爲根的結點的個數
2     int Size(BinTreeNode<T> *subTree) const
3  { 4         if (subTree == NULL)    //遞歸結束,空樹結點個數爲0
5  { 6             return 0; 7  } 8         return 1 + Size(subTree->leftChild) + Size(subTree->rightChild); 9     }

二叉樹的高度

 1     //計算二叉數以subTree爲根的高度
 2     int Height(BinTreeNode<T> *subTree)  3  {  4         if (subTree == NULL)    //遞歸結束,空樹高度爲0
 5  {  6             return 0;  7  }  8         int i = Height(subTree->leftChild);  9         int j = Height(subTree->rightChild); 10         return i < j ? j + 1 : i + 1; 11     }

 以廣義表的形式輸出二叉樹

 1     void PrintBinTree(BinTreeNode<T> *BT)  2  {  3         if (BT != NULL)    //樹爲空時結束遞歸
 4  {  5             cout << BT->data;  6             if (BT->leftChild != NULL || BT->rightChild != NULL)  7  {  8                 cout << '(';  9                 if (BT->leftChild!=NULL) 10  { 11                     PrintBinTree(BT->leftChild); 12  } 13                 cout << ','; 14                 if (BT->rightChild != NULL) 15  { 16                     PrintBinTree(BT->rightChild); 17  } 18                 cout << ')'; 19  } 20  } 21     }

求二叉樹某結點的父節點

 1     //從結點subTree開始,搜索結點current的父節點,找到返回父節點的地址,找不到返回NULL
 2     BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current)  3  {  4         if (subTree == NULL)  5  {  6             return NULL;  7  }  8         if (subTree->leftChild == current || subTree->rightChild == current)    //若是找到,返回父節點subTree
 9  { 10             return subTree; 11  } 12         BinTreeNode<T>* p; 13         if (p = Parent(subTree->leftChild, current) != NULL)    //遞歸在左子樹中搜索
14  { 15             return p; 16  } 17         else
18  { 19             return Parent(subTree->rightChild, current);    //遞歸右子樹中搜索
20  } 21     }

二叉樹的銷燬

 1     //二叉樹的銷燬函數
 2     void Destroy(BinTreeNode<T> *&subTree)  3  {  4         if (subTree != NULL)  5  {  6             Destroy(subTree->leftChild);  7             Destroy(subTree->rightChild);  8             delete subTree;  9             subTree = NULL; 10  } 11     }

 判斷兩顆二叉樹是否相等

 1     //判斷兩顆二叉樹是否相等
 2     bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b)  3  {  4         if (a == NULL&&b == NULL)    //二者都爲空
 5  {  6             return true;  7  }  8         if (a != NULL&&b != NULL&&a->data == b->data&&equal(a->leftChild, b->leftChild) && equal(a->rightChild, b->rightChild))    //二者都不爲空,且二者的結點數據相等,且二者的左右子樹的結點都相等
 9  { 10             return true; 11  } 12         return false; 13     }

 

 完整代碼:
 
 1 //結點類型
 2 template <typename T>
 3 struct BinTreeNode  4 {  5     T data;                                                                                                        //結點中存儲的數據
 6     BinTreeNode<T> *leftChild, *rightChild;                                                                        //左子樹和右子樹
 7     BinTreeNode() : leftChild(NULL), rightChild(NULL) {}                                                           //無參構造函數
 8     BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) : data(x), leftChild(l), rightChild(r) {} //帶默認值的有參構造參數
 9 };  10 
 11 //二叉樹類
 12 template <typename T>
 13 class BinaryTree  14 {  15 public:  16 
 17 //==========二叉樹構造與析構==========//
 18 
 19     //構造函數
 20  BinaryTree() : root(NULL) {}  21 
 22     //指定結束標誌的構造函數
 23  BinaryTree(T value) : RefValue(value), root(NULL) {}  24 
 25     //析構函數
 26     ~BinaryTree() { Destroy(root); }  27 
 28 //==========二叉樹的建立==========//
 29 
 30     //使用廣義表建立二叉樹,以'#'字符表明結束
 31     void CreateBinTree() { CreateBinTree(root); }  32 
 33     //前序遍歷建立二叉樹(前序遍歷的應用),用#表示空結點
 34     void CreateBinTree_PreOrder() { CreateBinTree_PreOrder(root); }  35 
 36     //使用先序遍歷和中序遍歷建立二叉樹
 37     void CreateBinTreeBy_Pre_In(const char *pre, const char *in)  38  {  39         int n = strlen(pre);  40         CreateBinTreeBy_Pre_In(root, pre, in, n);  41  }  42 
 43     //使用後序遍歷和中序遍歷建立二叉樹
 44     void CreateBinTreeBy_Post_In(const char *post, const char *in)  45  {  46         int n = strlen(post);  47         CreateBinTreeBy_Post_In(root, post, in, n);  48  }  49 
 50 //==========二叉樹的遍歷==========//
 51 
 52     //先序遍歷(遞歸)
 53     void PreOrder() { PreOrder(root); }  54 
 55     //中序遍歷(遞歸)
 56     void InOrder() { InOrder(root); }  57 
 58     //後序遍歷(遞歸)
 59     void PostOrder() { PostOrder(root); }  60 
 61     //先序遍歷(非遞歸)
 62     void PreOrder_NoRecurve() { PreOrder_NoRecurve(root); }  63 
 64     //中序遍歷(非遞歸)
 65     void InOrder_NoRecurve() { InOrder_NoRecurve(root); }  66 
 67     //後序遍歷(非遞歸)
 68     void PostOrder_NoRecurve() { PostOrder_NoRecurve(root); }  69 
 70     //層次遍歷(非遞歸)
 71     void LevelOrder() { LevelOrder(root); }  72 
 73 //==========獲取結點==========//
 74 
 75     //獲取二叉樹的根節點
 76     BinTreeNode<T> *getRoot() const
 77  {  78         return root;  79  }  80 
 81     //獲取current結點的父節點
 82     BinTreeNode<T> *Parent(BinTreeNode<T> *current)  83  {  84         return (root == NULL || root == current) ? NULL : Parent(root, current); //若是沒有根節點或current結點就是root結點,就沒有父節點
 85  }  86 
 87     //獲取current結點的左結點
 88     BinTreeNode<T> *LeftChild(BinTreeNode<T> *current)  89  {  90         return (current != NULL) ? current->leftChild : NULL;  91  }  92 
 93     //獲取current結點的右結點
 94     BinTreeNode<T> *RightChild(BinTreeNode<T> *current)  95  {  96         return (current != NULL) ? current->rightChild : NULL;  97  }  98 
 99 //==========成員函數==========//
100 
101     //銷燬函數
102     void Destroy() { Destroy(root); } 103 
104     //拷貝二叉樹(前序遍歷的應用)
105     BinaryTree(BinaryTree<T> &s) 106  { 107         root = Copy(s.getRoot()); 108  } 109 
110     //判斷兩顆二叉樹是否相等(前序遍歷的應用)
111     bool operator==(BinaryTree<T> &s) 112  { 113         return (equal(this->getRoot(), s.getRoot())); 114  } 115 
116     //計算二叉樹的結點的個數(後序遍歷的應用)
117     int Size() { return Size(root); } 118 
119     //計算二叉樹的高度(後序遍歷的應用)
120     int Height() { return Height(root); } 121 
122     //判斷二叉樹是否爲空
123     bool Empty() { return (root == NULL) ? true : false; } 124 
125     //以廣義表的形式輸出二叉樹(前序遍歷的應用)
126     void PrintBinTree() { PrintBinTree(root); } 127 
128 protected: 129 
130     //使用廣義表建立二叉樹函數,這裏以「字符」建立二叉樹,以'#'字符表明結束
131     void CreateBinTree(BinTreeNode<T> *&BT) 132  { 133         stack<BinTreeNode<T> *> s; 134         BT = NULL; 135         BinTreeNode<T> *p, *t; //p用來記住當前建立的節點,t用來記住棧頂的元素
136         int k;                 //k是處理左、右子樹的標記
137  T ch; 138         cin >> ch; 139 
140         while (ch != RefValue) 141  { 142             switch (ch) 143  { 144             case '(': //對(作處理
145  s.push(p); 146                 k = 1; 147                 break; 148 
149             case ')': //對)作處理
150  s.pop(); 151                 break; 152 
153             case ',': //對,作處理
154                 k = 2; 155                 break; 156 
157             default: 158                 p = new BinTreeNode<T>(ch); //構造一個結點
159                 if (BT == NULL)             //若是頭節點是空
160  { 161                     BT = p; 162  } 163                 else if (k == 1) //鏈入*t的左孩子
164  { 165                     t = s.top(); 166                     t->leftChild = p; 167  } 168                 else //鏈入*t的右孩子
169  { 170                     t = s.top(); 171                     t->rightChild = p; 172  } 173  } 174             cin >> ch; 175  } 176  } 177 
178     //建立二叉樹(利用已知的二叉樹的前序遍歷建立)用#表示空結點
179     void CreateBinTree_PreOrder(BinTreeNode<T> *&subTree) 180  { 181  T item; 182         if (cin >> item) 183  { 184             if (item != RefValue) 185  { 186                 subTree = new BinTreeNode<T>(item); //構造結點
187                 if (subTree == NULL) 188  { 189                     cout << "空間分配錯誤!" << endl; 190                     exit(1); 191  } 192                 CreateBinTree_PreOrder(subTree->leftChild);  //遞歸建立左子樹
193                 CreateBinTree_PreOrder(subTree->rightChild); //遞歸建立右子樹
194  } 195             else
196  { 197                 subTree == NULL; 198  } 199  } 200  } 201 
202     //使用先序遍歷和中序遍歷建立二叉樹
203     void CreateBinTreeBy_Pre_In(BinTreeNode<T> *&cur, const char *pre, const char *in, int n) 204  { 205         if (n <= 0) 206  { 207             cur = NULL; 208             return; 209  } 210         int k = 0; 211         while (pre[0] != in[k]) //再中序中找到pre[0]的值
212  { 213             k++; 214  } 215         cur = new BinTreeNode<T>(in[k]); //建立結點
216         CreateBinTreeBy_Pre_In(cur->leftChild, pre + 1, in, k); 217         CreateBinTreeBy_Pre_In(cur->rightChild, pre + k + 1, in + k + 1, n - k - 1); 218  } 219     //使用後序遍歷和中序遍歷建立二叉樹
220     void CreateBinTreeBy_Post_In(BinTreeNode<T> *&cur, const char *post, const char *in, int n) 221  { 222         if (n == 0) 223  { 224             cur = NULL; 225             return; 226  } 227 
228         char r = *(post + n - 1);    //根結點值
229         cur = new BinTreeNode<T>(r); //構造當前結點
230 
231         int k = 0; 232         const char *p = in; 233         while (*p != r) 234  { 235             k++; 236             p++; 237  } 238         CreateBinTreeBy_Post_In(cur->leftChild, post, in, k); 239         CreateBinTreeBy_Post_In(cur->rightChild, post + k, p + 1, n - k - 1); 240  } 241 
242     //先序遍歷(遞歸)
243     void PreOrder(BinTreeNode<T> *&subTree) 244  { 245         if (subTree != NULL) 246  { 247             cout << subTree->data << " "; 248             PreOrder(subTree->leftChild); 249             PreOrder(subTree->rightChild); 250  } 251  } 252 
253     //中序遍歷(遞歸)
254     void InOrder(BinTreeNode<T> *&subTree) 255  { 256         if (subTree != NULL) 257  { 258             InOrder(subTree->leftChild); 259             cout << subTree->data << " "; 260             InOrder(subTree->rightChild); 261  } 262  } 263 
264     //後序遍歷(遞歸)
265     void PostOrder(BinTreeNode<T> *&subTree) 266  { 267         if (subTree != NULL) 268  { 269             PostOrder(subTree->leftChild); 270             PostOrder(subTree->rightChild); 271             cout << subTree->data << " "; 272  } 273  } 274 
275     //先序遍歷(非遞歸)
276     void PreOrder_NoRecurve(BinTreeNode<T> *p) 277  { 278         stack<BinTreeNode<T> *> S; 279         BinTreeNode<T> *t; 280         S.push(p);         //根節點進棧
281         while (!S.empty()) //當棧不爲空
282  { 283             t = S.top(); //p先記住棧頂元素,而後棧頂出棧
284  S.pop(); 285             cout << t->data << " ";    //訪問元素
286             if (t->rightChild != NULL) //右孩子不爲空,右孩子近棧
287  { 288                 S.push(t->rightChild); 289  } 290             if (t->leftChild != NULL) //左孩子不爲空,左孩子進棧
291  { 292                 S.push(t->leftChild); 293  } 294  } 295  } 296 
297     //中序遍歷(非遞歸)
298     void InOrder_NoRecurve(BinTreeNode<T> *root) 299  { 300         if (root == NULL) 301             return; 302         stack<BinTreeNode<T> *> s; 303  s.push(root); 304         while (!s.empty()) 305  { 306             while (s.top()->leftChild != NULL) //將左結點依次入棧
307  { 308                 s.push(s.top()->leftChild); 309  } 310             while (!s.empty()) 311  { 312                 BinTreeNode<T> *cur = s.top(); 313                 cout << cur->data << " "; 314  s.pop(); 315                 if (cur->rightChild != NULL) 316  { 317                     s.push(cur->rightChild); 318                     break; 319  } 320  } 321  } 322  } 323 
324     //後序遍歷(非遞歸)
325     void PostOrder_NoRecurve(BinTreeNode<T> *p) 326  { 327         if (root == NULL) 328             return; 329         stack<BinTreeNode<T> *> s; 330  s.push(p); 331         BinTreeNode<T> *lastPop = NULL; 332         while (!s.empty()) 333  { 334             while (s.top()->leftChild != NULL) 335                 s.push(s.top()->leftChild); 336             while (!s.empty()) 337  { 338                 //右葉子結點 || 沒有右結點
339                 if (lastPop == s.top()->rightChild || s.top()->rightChild == NULL) 340  { 341                     cout << s.top()->data << " "; 342                     lastPop = s.top(); 343  s.pop(); 344  } 345                 else if (s.top()->rightChild != NULL) 346  { 347                     s.push(s.top()->rightChild); 348                     break; 349  } 350  } 351  } 352  } 353 
354     //層次遍歷(非遞歸)
355     void LevelOrder(BinTreeNode<T> *p) 356  { 357         queue<BinTreeNode<T> *> Q; 358         Q.push(p); //根節點進隊
359         BinTreeNode<T> *t; 360         while (!Q.empty()) 361  { 362             t = Q.front(); //t先記住隊頭,再將隊頭出隊
363  Q.pop(); 364             cout << t->data << " "; //訪問隊頭元素的數據
365 
366             if (t->leftChild != NULL) 367  { 368                 Q.push(t->leftChild); 369  } 370 
371             if (t->rightChild != NULL) 372  { 373                 Q.push(t->rightChild); 374  } 375  } 376  } 377 
378     //從結點subTree開始,搜索結點current的父節點,找到返回父節點的地址,找不到返回NULL
379     BinTreeNode<T> *Parent(BinTreeNode<T> *subTree, BinTreeNode<T> *current) 380  { 381         if (subTree == NULL) 382  { 383             return NULL; 384  } 385         if (subTree->leftChild == current || subTree->rightChild == current) //若是找到,返回父節點subTree
386  { 387             return subTree; 388  } 389         BinTreeNode<T> *p; 390         if (p = Parent(subTree->leftChild, current) != NULL) //遞歸在左子樹中搜索
391  { 392             return p; 393  } 394         else
395  { 396             return Parent(subTree->rightChild, current); //遞歸右子樹中搜索
397  } 398  } 399 
400     //二叉樹的銷燬
401     void Destroy(BinTreeNode<T> *&subTree) 402  { 403         if (subTree != NULL) 404  { 405             Destroy(subTree->leftChild); 406             Destroy(subTree->rightChild); 407             delete subTree; 408             subTree = NULL; 409  } 410  } 411 
412     //複製二叉樹函數,返回一個指針,給出一個以originNode爲根複製的二叉樹的副本
413     BinTreeNode<T> *Copy(BinTreeNode<T> *originNode) 414  { 415         if (originNode == NULL) 416  { 417             return NULL; 418  } 419         BinTreeNode<T> *temp = new BinTreeNode<T>; //建立根結點
420         temp->data = originNode->data; 421         temp->leftChild = Copy(originNode->leftChild); 422         temp->rightChild = Copy(originNode->rightChild); 423         return temp; 424  } 425 
426     //判斷兩顆二叉樹是否相等
427     bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b) 428  { 429         if (a == NULL && b == NULL) //二者都爲空
430  { 431             return true; 432  } 433         if (a != NULL && b != NULL && a->data == b->data && equal(a->leftChild, b->leftChild) && equal(a->rightChild, b->rightChild)) //二者都不爲空,且二者的結點數據相等,且二者的左右子樹的結點都相等
434  { 435             return true; 436  } 437         return false; 438  } 439 
440     //計算二叉樹以subTree爲根的結點的個數
441     int Size(BinTreeNode<T> *subTree) const
442  { 443         if (subTree == NULL) //遞歸結束,空樹結點個數爲0
444  { 445             return 0; 446  } 447         return 1 + Size(subTree->leftChild) + Size(subTree->rightChild); 448  } 449 
450     //計算二叉數以subTree爲根的高度
451     int Height(BinTreeNode<T> *subTree) 452  { 453         if (subTree == NULL) //遞歸結束,空樹高度爲0
454  { 455             return 0; 456  } 457         int i = Height(subTree->leftChild); 458         int j = Height(subTree->rightChild); 459         return i < j ? j + 1 : i + 1; 460  } 461 
462     //以廣義表的形式輸出二叉樹
463     void PrintBinTree(BinTreeNode<T> *BT) 464  { 465         if (BT != NULL) //樹爲空時結束遞歸
466  { 467             cout << BT->data; 468             if (BT->leftChild != NULL || BT->rightChild != NULL) 469  { 470                 cout << '('; 471                 if (BT->leftChild != NULL) 472  { 473                     PrintBinTree(BT->leftChild); 474  } 475                 cout << ','; 476                 if (BT->rightChild != NULL) 477  { 478                     PrintBinTree(BT->rightChild); 479  } 480                 cout << ')'; 481  } 482  } 483  } 484 
485 private: 486     BinTreeNode<T> *root; //根節點
487     T RefValue;           //數據輸入中止的標誌,須要一個構造函數
488 };

 

相關文章
相關標籤/搜索