前序中序、後序中序、層序中序創建二叉樹

前序中序創建二叉樹


先寫一個只能保存單個字符的算法:

/**
 *@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 時,均不滿足內層循環的三個判斷,因此不會再進行遞歸,所以可以省略,但是寫上的話,倒也可以提升一點運行效率的。

本次記錄到此結束!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章