树状打印任意形式二叉树
高度为8的二叉树打印最终效果:
二叉树高度大概为6、7时,宽度就超过了控制台的最大宽度,所以没有用cout输出,而是输出为一个文件,所以声明了一个ofstream(out_file)。
注:输出后用记事本和sublime都没有预期的显示效果,需要用Notepad打开。
为了压缩显示面积,每个节点(节点宽度最好是奇数)之间相隔为1,原本树的三角形表示用_、/、\代替。
因为有些二叉树不是完全二叉树,没有子节点的时候不需要打印连接的线,为了方便判断以及层次遍历,先用一个string类型的数组list保存一下要打印的节点内容。
下方代码中code是HFNode的一个成员变量,保存节点的顺序,比如根节点的左孩子是0,右孩子是1,根节点左孩子的右孩子就是01(即Huffman树的译码规则)。另一个成员变量id就是要打印的节点内容。
默认数组最大长度为1024,足够打印10层的二叉树。(试着打过一次17层的树,文件有20M,Notepad加载相当缓慢。)
之后比较麻烦的地方就是空格、下划线的计数,可以自己画一个方格布数格子。
部分源代码如下:
template <class T>
void Huffman<T>::PrintTree(string out_file_name)
{
ofstream out_file(out_file_name);
int height = 0;
int i, j, k ,l , pos;
string str;
string list[1024];
//初始化
for (i = 0; i < 1024; i++)
list[i] = " ";
list[1] = "XXX";
//层次遍历,但不能遍历root,因为root的code为空
if (root == NULL)
return;
queue<HFNode<T>*> q;
q.push(root->LeftChild);
q.push(root->RightChild);
while (!q.empty())
{
for (i = 0; i < q.size(); i++)
{
HFNode<T>* p = q.front();
q.pop();
if (p->LeftChild)
q.push(p->LeftChild);
if (p->RightChild)
q.push(p->RightChild);
if (!p)
break;
if (p->code.length() > height)
height = p->code.length();
//先利用code找到对应的数组位置
pos = 1;
str = p->code;
for (j = 0; j < str.length(); j++)
{
pos *= 2;
if (str[j] == '1')
pos++;
}
//进行赋值
if (p->id != -1)
list[pos] = std::to_string(p->id);
else
list[pos] = "XXX";
}
}
height++;
//先打印节点
int s = pow(2, height) - 1;
int h = height;
for (i = 1; i <= s; i++)
{
for (j = 0; j < pow(2, h - 1) - 1; j++)
out_file << " ";
out_file << setw(3) << setfill('0') << list[i];
for (j = 0; j < pow(2, h - 1) - 1; j++)
out_file << " ";
out_file << ' ';
//打印完节点后,下一行打印连接线条
if (i == pow(2, height - h + 1) - 1)
{
out_file << endl;
if (i == s)
break;
for (k = i+1; k <= 2 * i + 1; k++)
{
if (list[k] == " ")
for (l = 0; l < pow(2, h) - 1; l++)
out_file << ' ';
else
{
if (k % 2 == 0)
{
for (l = 0; l < pow(2, h - 1); l++)
out_file << ' ';
for (l = 0; l < pow(2, h - 1) - 2; l++)
out_file << '_';
out_file << '/';
}
else
{
out_file << '\\';
for (l = 0; l < pow(2, h - 1) - 2; l++)
out_file << '_';
for (l = 0; l < pow(2, h - 1); l++)
out_file << ' ';
}
}
out_file << ' ';
}
out_file << endl;
//连接线第二行的\和/
for (k = i + 1; k <= 2 * i + 1; k++)
{
if (list[k] == " ")
for (l = 0; l < pow(2, h) - 1; l++)
out_file << ' ';
else
{
if (k % 2 == 0)
{
for (l = 0; l < pow(2, h - 1) - 1; l++)
out_file << ' ';
out_file << '/';
for (l = 0; l < pow(2, h - 1) - 1; l++)
out_file << ' ';
}
else
{
for (l = 0; l < pow(2, h - 1) - 1; l++)
out_file << ' ';
out_file << '\\';
for (l = 0; l < pow(2, h - 1) - 1; l++)
out_file << ' ';
}
}
out_file << ' ';
}
out_file << endl;
h--;
}
}
}