二叉查找树BinSearchTree:命令行打印二叉树

14 篇文章 0 订阅

整体思路

首先定义了打印树的迭代函数printTreeRec (),它的参数是当前节点,函数从根节点进入,判断不是叶子节点后打印其左孩子和右孩子,如此迭代,直到迭代到叶子节点。

在打印过程中为了格式化,整体上分了四类节点:

四类节点图示

  • 分类1:是分类2的一种特殊情况,这是根节点没有右孩子的情况,无法调用它的父母,所以先单独判断;
  • 分类2:右孩子链的结尾换行,此情况为了避免与左子树根节点的打印重合,又加入条件必须是是父节点的右孩子节点;
  • 分类3:左子树开头情况,要统计tab数和“|”的打印位置;其以是否是叶子节点又分为两种情况;
  • 分类4:右子树链的普通情况,也是最简单的情况,因为它在一行的中间,所以不需要有特殊输出格式;

部分代码

template<typename T>
void BinSearchTree<T>::printTreeRec(Node* tempRoot) {
	//分类1:根节点没有右孩子的情况,无法调用它的父母,所以先单独判断
	if(tempRoot==root && tempRoot->right==NULL)		
		cout << tempRoot->item << "\n";	
	//分类2:右孩子链的结尾换行,此情况为了避免与左子树根节点的打印重合,又加入条件必须是是父节点的右孩子节点
	else if (tempRoot->right == NULL && tempRoot->parent->right==tempRoot)
		cout << tempRoot->item<<"\n";
	//分类3:左子树开头情况,要统计tab数和“|”的打印位置
	else if (tempRoot != root && tempRoot->parent->left == tempRoot) {
		Node* temp = tempRoot->parent;	//创建临时节点,用来遍历当前节点的祖宗节点,判断tab数和“|”的打印位置
		vector <string> tab;	//创建向量tab用来储存tab和“|”
		//遍历当前节点的祖宗节点
		while (temp != root) {
			if(temp->parent->left != NULL && temp->item != 101) 
				tab.push_back("│\t");	//如果此节点未被标记,则需要打印“|”连接
			else 
				tab.push_back("\t"); //如果此节点被标记为101则说明以打印,不需要再打印“|”连接
			temp = temp->parent;
		}

		//将tab向量反向输出
		for (int i = tab.size(); i >0; i--) {
			cout << tab[i-1];
		}
//分类3.1:如果这个节点既是左子树开始,又是左子树结尾
		if (tempRoot->right == NULL) {	
			cout << "└─────\t" << tempRoot->item << "\n";
			tempRoot->item = 101;	//标记已输出的右子树根
		}
//分类3.2:如果这个节点仅是左子树开始,他还有右孩子
		else {	
			cout << "└─────\t" << tempRoot->item << "────\t";
			tempRoot->item = 101;	//标记已输出的右子树根
		}
	}
	else cout << tempRoot->item <<"────\t";	//分类4:右子树链的普通情况


	//递归代码
	if (tempRoot->right != NULL) {
		printTreeRec(tempRoot->right);
	}
	if (tempRoot->left != NULL) {
		printTreeRec(tempRoot->left);		
	}
	if (tempRoot->right == NULL && tempRoot->left == NULL) return;

}

template<typename T>
void BinSearchTree<T>::printTree()
{
	printTreeRec(root);
}


实验总结

在打印时最重要的是给二叉树的节点进行合理而全面的情况分析。在本实验中我将其分为4类节点,因为是横向打印二叉树,所以右孩子的打印不需要换行,只需要考虑这个节点是否还有右孩子,有的话继续打印,没有则进行换行操作,并回溯到其父节点判断是否有左孩子。整个遍历过程是一个深度优先搜索

其中比较复杂的情况是每行打印的第一个左孩子需要考虑到tab数和“│”的打印位置。对于这种情况,建立一个vector向量进行数据储存,每次换行后从该节点向根回溯,遇到没有输出的左孩子储存“│\t”,其他则只储存“\t”,然后进行倒序输出,并将自身标记为101表示已输出(随机生成树的节点最大值为100的情况),后面不用再打印“│”符号了。

其中比较容易出bug的地方是根节点和节点的双重身份(例如既是左孩子又是一行的最后一个),为此我分了4个判断语句进行准确的分类,排除了这些bug。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值