前序中序、后序中序、层序中序创建二叉树

前序中序创建二叉树


先写一个只能保存单个字符的算法:

/**
 *@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 时,均不满足内层循环的三个判断,因此不会再进行递归,所以可以省略,但是写上的话,倒也可以提升一点运行效率的。

本次记录到此结束!

你可能感兴趣的:(二叉树)