本篇文章將介紹二叉樹的常見構造方法,總體涵蓋控制台輸入字符串構造和根據字符串構造,兩者構造的區別是,前者構造序列需要從控制台輸入,后者構造序列可以通過現有字符串直接構造;並且通過遞歸與迭代兩種思路進行構造,我們將先通過遞歸進行構造,然后將遞歸轉化為迭代,如果不知道如何將遞歸轉化為迭代,請參看文章數據結構——遞歸與非遞歸。
假設有如下一顆二叉樹:
我們可以根據圖示二叉樹寫出他的前序序列為:ABDC。如果反過來,已知前序序列ABDC,我們能不能根據前序序列畫出二叉樹呢,答案是不能。我們可以將二叉樹稍微改造一下,用#代表空結點,改造結果如下所示:
我們寫出改造后的二叉樹的前序序列:AB#D##C##。現在我們就可以根據改造后的二叉樹前序序列唯一地構造二叉樹了。
控制台遞歸構造,就是將前序序列通過控制台輸入的方式逐一錄入,然后將錄入的前序序列通過遞歸進行構造。我們將二叉樹采用二叉鏈表的方式進行存儲,即結點包含三部分,數據域,左孩子和右孩子。如下圖所示:
給出二叉樹結點的定義,代碼如下:
1 /* 二叉樹結點 */ 2 template <typename DataType> 3 struct BiNode 4 { 5 DataType data; 6 BiNode<DataType>* lChild; 7 BiNode<DataType>* rChild; 8 };
我們給出二叉樹的定義,代碼如下:
1 template <typename DataType> 2 class BiTree 3 { 4 public: 5 BiTree() { root = create(); } // 構造函數 6 ~BiTree(); // 析構函數 7 private: 8 BiNode<DataType>* create(); // 控制台遞歸構造二叉樹 9 BiNode<DataType>* root; // 二叉樹根結點 10 };
接下來我們實現控制台遞歸構造二叉樹的方法 BiNode<DataType>* create();代碼如下:
1 template <typename DataType> 2 BiNode<DataType>* BiTree<DataType>::create() 3 { 4 BiNode<DataType>* bt; 5 char ch; 6 std::cin >> ch; // 控制台錄入 7 if ('#' == ch) 8 { 9 bt = nullptr; 10 } 11 else 12 { 13 bt = new BiNode<DataType>; 14 bt->data = ch; 15 bt->lChild = create(); // 遞歸構造左子樹 16 bt->rChild = create(); // 遞歸構造右子樹 17 } 18 return bt; 19 }
字符串遞歸構造,就是傳入一個字符串前序序列作為參數,然后進行遞歸構造二叉樹。我們依舊采用二叉鏈表的方式,本文二叉樹的存儲結構我們一直采用二叉鏈表的方式。
修改二叉樹的定義如下:
1 template <typename DataType> 2 class BiTree 3 { 4 public: 5 BiTree() { root = create(); } 6 BiTree(std::string tree, int index) { root = create(tree, index); } 7 ~BiTree(); 8 private: 9 BiNode<DataType>* create(); 10 BiNode<DataType>* create(std::string tree, int& index); 11 BiNode<DataType>* root; // 二叉樹根節點 12 };
接下來我們實現字符串遞歸構造二叉樹的方法 BiNode<DataType>* create(std::string tree, int& index);代碼如下:
1 template <typename DataType> 2 BiNode<DataType>* BiTree<DataType>::create(std::string tree, int& index) 3 { 4 BiNode<DataType>* bt; 5 char ch; 6 ch = tree[index]; 7 if ('#' == ch) 8 { 9 bt = nullptr; 10 } 11 else 12 { 13 bt = new BiNode<DataType>; 14 bt->data = ch; 15 bt->lChild = create(tree, ++index); 16 bt->rChild = create(tree, ++index); 17 } 18 return bt; 19 }
我們將字符串遞歸構造改寫成字符串迭代構造。
修改二叉樹定義, 代碼如下:
1 template <typename DataType> 2 class BiTree 3 { 4 public: 5 BiTree() { root = create(); } 6 BiTree(std::string tree, int index) { root = create(tree, index); } 7 BiTree(std::string tree) { createIter(tree, 0); } 8 ~BiTree(); 9 private: 10 BiNode<DataType>* create(); 11 BiNode<DataType>* create(std::string tree, int& index); 12 void createIter(std::string tree, int index); 13 BiNode<DataType>* root; 14 };
接下來我們實現字符串迭代構造二叉樹的方法 void createIter(std::string tree, int index);代碼如下:
1 template <typename DataType> 2 void BiTree<DataType>::createIter(std::string tree, int index) 3 { 4 root = new BiNode<DataType>; 5 root->data = '*'; 6 BiNode<DataType>* bt = root; 7 BiNode<DataType>* stack[20]; 8 int top = -1; // 棧頂指針 9 10 while ('#' != tree[index] || -1 != top) 11 { 12 while ('#' != tree[index]) 13 { 14 if (bt == nullptr || '*' != bt->data) 15 { 16 bt = new BiNode<DataType>; 17 } 18 bt->data = tree[index]; 19 stack[++top] = bt; // 保存現場 20 ++index; // 修改局部變量 21 if ('#' == tree[index]) 22 { 23 bt->lChild = nullptr; 24 } 25 else { 26 bt->lChild = new BiNode<DataType>; 27 bt = bt->lChild; 28 bt->data = '*'; 29 } 30 } 31 32 bt = stack[top--]; // 恢復現場 33 ++index; // 修改局部變量 34 if ('#' != tree[index]) 35 { 36 bt->rChild = new BiNode<DataType>; 37 bt = bt->rChild; 38 bt->data = '*'; 39 } 40 else 41 { 42 bt->rChild = nullptr; 43 } 44 } 45 }
我們可以根據前序序列和中序序列唯一地確定二叉樹,確定方法請參考文獻2。
修改二叉樹定義, 代碼如下:
1 template <typename DataType> 2 class BiTree 3 { 4 public: 5 BiTree() { root = create(); } 6 BiTree(std::string tree, int index) { root = create(tree, index); } 7 BiTree(std::string tree) { createIter(tree, 0); } 8 BiTree(std::string preOrder, std::string inOrder, int n) { root = create(preOrder, inOrder, n); } 9 ~BiTree(); 10 private: 11 BiNode<DataType>* create(); 12 BiNode<DataType>* create(std::string tree, int& index); 13 void createIter(std::string tree, int index); 14 BiNode<DataType>* create(std::string preOrder, std::string inOrder, int length); 15 16 BiNode<DataType>* root; 17 };
接下來我們實現字符串遞歸構造二叉樹的方法BiNode<DataType>* create(std::string preOrder, std::string inOrder, int length);代碼如下:
1 template <typename DataType> 2 BiNode<DataType>* BiTree<DataType>::create(std::string preOrder, std::string inOrder, int n) 3 { 4 BiNode<DataType>* bt; 5 6 if (0 == n) 7 { 8 bt = nullptr; 9 } 10 else 11 { 12 bt = new BiNode<DataType>; 13 bt->data = preOrder[0]; 14 int n = inOrder.find(preOrder[0], 0); 15 std::string lPreOrder = preOrder.substr(1, n); 16 std::string lInOrder = inOrder.substr(0, n); 17 std::string rPreOrder = preOrder.substr(n + 1, preOrder.size() - 1 - n); 18 std::string rInOrder = inOrder.substr(n + 1, inOrder.size() - 1 - n); 19 bt->lChild = create(lPreOrder, lInOrder, n); 20 bt->rChild = create(rPreOrder, rInOrder, inOrder.size() - 1 - n); 21 } 22 23 return bt; 24 }
1、[二叉樹地建立方法總結](https://www.cnblogs.com/llhthinker/p/4906631.html)
2、數據結構——從概念到C++實現(第三版) 王紅梅、王慧、王新穎 編著