前序中序創建二叉樹
先寫一個只能保存單個字符的算法:
/**
*@param pre:前序序列
*@param in:後序序列
*/
template <class T> BinaryTree<T>* CreateBinaryTreeByPreOrderInOrder(string pre, string in) {
if(pre.length() == 0) {
return NULL;
}
int root = in.find(pre[0]);
BinaryTree<T> *tree = (BinaryTree<T> *)malloc(sizeof(BinaryTree<T>));
tree -> data = pre[0];
tree -> lchild = CreateBinaryTreeByPreOrderInOrder<char>(pre.substr(1, root), in.substr(0, root));
tree -> rchild = CreateBinaryTreeByPreOrderInOrder<char>(pre.substr(root + 1), in.substr(root + 1));
return tree;
}
算法很簡單,一下就能看懂,但是侷限性也很大,就是二叉樹的數據只能保存單個字符,這樣模板毫無作用,但我想寫成通用的,因此我有了第一個想法:
1、就是編寫一個類似 “substr” 的函數,用來提取 “*T” 的部分數據並返回。但是很快我就否定了,因爲這樣需要大量的 new ,至少我必須用大量的 new。於是我有了第二個想法,給函數再添加四個參數。
2、上述代碼中, “substr” 使用了兩次,因此我直接把這兩次使用的四個參數作爲函數參數,也相當於變相的實現的 “substr”。
從而新的代碼如下(因此序列長度是一樣的,因此給定長度 length, 則可以省去一個參數):
template <class T> BinaryTree<T>* CreateBinaryTreeByPreOrderInOrder(const T *pre, int s1, const T *in, int s2, int length) {
if(length == 0) {
return NULL;
}
int ltreeLength = 0;
int rtreeLength = 0;
for(int i = s2; i < s2 + length; i++) {
if(in[i] == pre[s1]) {
break;
}
ltreeLength++;
}
rtreeLength = length - ltreeLength - 1;
BinaryTree<T> *tree = (BinaryTree<T> *)malloc(sizeof(BinaryTree<T>));
tree -> data = pre[s1];
tree -> lchild = CreateBinaryTreeByPreOrderInOrder<T>(pre, s1 + 1, in, s2, ltreeLength);
tree -> rchild = CreateBinaryTreeByPreOrderInOrder<T>(pre, s1 + 1 + ltreeLength, in, s2 + 1 + ltreeLength, rtreeLength);
return tree;
}
/**
*前序中序創建二叉樹函數接口
*/
template <class T> BinaryTree<T>* CreateBinaryTreeByPreOrderInOrder(const T *pre, const T *in, int length) {
return CreateBinaryTreeByPreOrderInOrder<T>(pre, 0, in, 0, length);
}
後序中序創建二叉樹
後序中序創建二叉樹的思路和前序中序創建二叉樹的思路差不多,代碼如下:
template <class T> BinaryTree<T>* CreateBinaryTreeByPostOrderInOrder(const T *post, int s1, const T *in, int s2, int length) {
if(length == 0) {
return NULL;
}
int ltreeLength = 0;
int rtreeLength = 0;
for(int i = s2; i < s2 + length; i++) {
if(in[i] == post[s1 + length - 1]) {
break;
}
ltreeLength++;
}
rtreeLength = length - ltreeLength - 1;
BinaryTree<T> *tree = (BinaryTree<T> *)malloc(sizeof(BinaryTree<T>));
tree -> data = post[s1 + length - 1];
tree -> lchild = CreateBinaryTreeByPostOrderInOrder<T>(post, s1, in, s2, ltreeLength);
tree -> rchild = CreateBinaryTreeByPostOrderInOrder<T>(post, s1 + ltreeLength, in, s2 + 1 + ltreeLength, rtreeLength);
return tree;
}
/**
*後序中序創建二叉樹函數接口
*/
template <class T> BinaryTree<T>* CreateBinaryTreeByPostOrderInOrder(const T *post, const T *in, int length) {
return CreateBinaryTreeByPostOrderInOrder<T>(post, 0, in, 0, length);
}
層序中序創建二叉樹
層序中序創建二叉樹,總的思路和前兩個差不多,但是因爲層序中左右子樹的序列是交錯的,因此需要做一些處理。
首先可以肯定的是每次的遞歸只返回一個節點,但是因爲層序的左右子樹的序列是交錯的,因此必須設置一個標識,用來標識是否已經找到左子樹,或者已經找到右子樹,或者找到根節點,否則的話,即使已經找到某個節點,那麼遞歸返回後,由於層序左右子樹序列的交錯,將會有新的節點再次進入與之前同樣的遞歸過程,從而導致之前找到的節點被新找到的節點所覆蓋,具體情況,以層序序列:“ABCDE”,中序序列:“DBACE”,構成的二叉樹手動模擬一下即可。
層序中序創建二叉樹代碼如下:
template <class T> BinaryTree<T>* CreateBinaryTreeByLevelOrderInOrder(const T *level, int s1, int e1, const T *in, int s2, int e2) {
int root;
bool isFindRoot = false;
bool isFindLTree = false;
bool isFindRTree = false;
BinaryTree<T> *tree = (BinaryTree<T> *)malloc(sizeof(BinaryTree<T>));
for(int i = s1; i <= e1; i++) {
for(int j = s2; j <= e2; j++) {
if(!isFindRoot && level[s1] == in[j]) {
root = j;
isFindRoot = true;
tree -> data = level[s1];
tree -> lchild = NULL;
tree -> rchild = NULL;
break;
}
//在層序中查找中序中左子樹的根節點
if(!isFindLTree && level[i] == in[j] && j < root) {
tree -> lchild = CreateBinaryTreeByLevelOrderInOrder<T>(level, i, e1, in, s2, root - 1);
isFindLTree = true;
break;
}
//在層序中查找中序中右子樹的根節點
if(!isFindRTree && level[i] == in[j] && j > root) {
tree -> rchild = CreateBinaryTreeByLevelOrderInOrder<T>(level, i, e1, in, root + 1, e2);
isFindRTree = true;
break;
}
}
//建立完成
if(isFindRoot && isFindLTree && isFindRTree) {
break;
}
}
return tree;
}
/**
*層序中序創建二叉樹函數接口
*/
template <class T> BinaryTree<T>* CreateBinaryTreeByLevelOrderInOrder(const T *level, const T *in, int length) {
return CreateBinaryTreeByLevelOrderInOrder<T>(level, 0, length - 1, in, 0, length - 1);
}
要說一下的是,遞歸結束條件是 s2 == e2, 但是此時內部循環只執行一次,而外部循環除了 i == s1 時,均不滿足內層循環的三個判斷,因此不會再進行遞歸,所以可以省略,但是寫上的話,倒也可以提升一點運行效率的。
本次記錄到此結束!