二叉树打印--子树不相交

题目来源: 同学微软面试题

题目:打印二叉树,子树不相交,每个节点间至少间隔5个空格。

层次打印,输出内容如下:

但子树相交啦,即bde子树 与 cf子树间在空间上交织在一起。不相交输出如下:

但要求两个节点间至少间隔5个空格,所以,应该为:

再来一个例子

 

实际上,每棵子树构成一个直角三角形。

 

解决思路:

每个节点需要两个额外的变量,记录该节点的横坐标,以及以该节点为根的子树最右边节点的横坐标。

比如,上图, a(1,3),  b(1, 2), d(1,1), c(2, 3), g(3,3) [第一个值:横坐标, 第二个值:子树最右节点横坐标]

 

void SubTreePrint(Node *root)
{
	if (root == NULL)
		return;

	
	if (root->left != NULL)
	{
		root->left->pos = root->pos;
		root->left->right_most = root->right_most;

		SubTreePrint(root->left);
		root->right_most = root->left->right_most;  //修正
	}

	if (root->right != NULL)
	{
		root->right->pos = root->right_most + 1;
		root->right->right_most = root->right_most + 1;

		SubTreePrint(root->right);
		root->right_most = root->right->right_most;  //修正
	}
}

注意到一个事实:子树左孩子pos等于父亲结点pos,右孩子pos为父亲结点pos+1.

同时,父亲结点的right_most 为 右孩子的right_most.

从左子树返回的时候,父节点的right_most 修正为左孩子right_most,即左子树的最右节点横坐标。

当从右子树返回时候,父节点的right_most 修正为右孩子right_most,即整棵树的最右节点横坐标。

这是一个坐标不断修正的过程,想象成一种后序遍历。

示例:

初始:根节点[1, 1]

从b的右孩子e返回,更新b; 从a的左孩子返回,更新a。

最右节点的pos 与 right_most 相等; 然后回溯的时候更新父节点的right_most.

 

整体代码:

struct Node
{
	Node *left;
	Node *right;
	char data;

	Node()
	{
		left = right = NULL;
	}

	int pos;
	int right_most;
};


void SubTreePrint(Node *root)
{
	if (root == NULL)
		return;

	
	if (root->left != NULL)
	{
		root->left->pos = root->pos;
		root->left->right_most = root->right_most;

		SubTreePrint(root->left);
		root->right_most = root->left->right_most;  //修正
	}

	if (root->right != NULL)
	{
		root->right->pos = root->right_most + 1;
		root->right->right_most = root->right_most + 1;

		SubTreePrint(root->right);
		root->right_most = root->right->right_most;  //修正
	}
}


//根据前序中序构建二叉树
Node *Rebuild(char *startPreOrder, char *endPreOrder, 
			  char *startInOrder, char *endInOrder)
{
	if (startPreOrder == NULL || endPreOrder == NULL
		|| startInOrder == NULL || endInOrder == NULL)
		return NULL;

	if (startPreOrder > endPreOrder || startInOrder > endInOrder)
		return NULL;

	char rootValue = *startPreOrder;

	Node *root = new Node;
	root->data = rootValue;
	root->left = root->right = NULL;

	if (startPreOrder == endPreOrder)
	{
		if (startInOrder == endInOrder && rootValue == *startInOrder)
			return root;
		else
			exit(1);
	}

	char *mid = startInOrder;
	while (mid < endInOrder && *mid != rootValue)
	{
		mid++;
	}

	if (mid == endInOrder && *mid != rootValue)
		exit(1);

	int leftTreeLen = mid - startInOrder;
	if (leftTreeLen > 0)
	{
		root->left = Rebuild(startPreOrder+1, startPreOrder+leftTreeLen, startInOrder, mid-1);
	}

	int rightTreeLen = endInOrder - mid;
	if (rightTreeLen > 0)
	{
		root->right = Rebuild(startPreOrder+leftTreeLen+1, endPreOrder, mid+1, endInOrder);
	}
	
	return root;
}


// 打印,层次遍历
void LevelPrint(Node *root)
{
	if (root == NULL)
		return;

	vector<Node*> v;

	unsigned curr = 0;
	unsigned last = 1;
	v.push_back(root);

	while (curr < v.size())
	{
		last = v.size();
		int index = 1;
		while (curr < last)
		{
			Node *node = v[curr];
			// 左孩子为空,打印空格
			if (node->pos != index) 
				cout << " ";
			else 
			{
				cout << node->data;

				if (node->left != NULL)
					v.push_back(node->left);
				if (node ->right != NULL)
					v.push_back(node->right);
				curr++;
			}

			for (int j = 0; j < 5; j++)
				cout << " ";

			index++;
		}
		cout << endl;
	}
}


int main()
{
	char *pre = "abdhiejkcfg";
	char *in  = "hdibjekafcg";

	//char *pre = "abdec";
	//char *in  = "dbeac";

	//char *pre = "abdhicfg";
	//char *in  = "hdibafcg";

	//char *pre = "abcdef";
	//char *in  = "abcdef";

	//char *pre = "abdcef";
	//char *in  = "bdaecf";

	//char *pre = "abdhicg";
	//char *in  = "hdibacg";

	Node *root = Rebuild(pre, pre+strlen(pre)-1, in, in+strlen(in)-1);

	root->pos = root->right_most = 1;
	SubTreePrint(root);

	LevelPrint(root);

	//标尺
	cout << "1     2     3     4     5" << endl;
	system("pause");
	return 0;
}

输出:

  

posted @ 2014-05-09 20:41  spch2008  阅读(1103)  评论(0)    收藏  举报