我一直在尝试使函数以一种漂亮的方式在控制台的侧面打印出一棵二叉树(在这种情况下是一棵红黑树)。我在互联网上找到了该算法,并将其修改为我的项目。
注意:在SO和其他网站上,我已经见过很多用Java打印二进制树的方法,但是它们大多使用Java的String或其他一些高级语言,而在C语言中,有时很难适应代码。下面的代码与我以漂亮的方式打印二叉树所获得的代码非常接近。
static void
rbt_display_treeview(Node *root, int depth, char *path, bool is_right)
{
const int spaces = 8;
if (root == NULL)
return;
depth++;
rbt_display_treeview(root->right, depth, path, true);
path[depth - 2] = 0;
if(is_right)
path[depth - 2] = 1;
if(root->left)
path[depth - 1] = 1;
printf("\n");
for (int i = 0; i < depth - 1; i++)
{
if (i == depth - 2)
printf("%c", is_right ? 218 : 192);
else if (path[i])
printf("%c", 179);
else
printf(" ");
for (int j = 1; j < spaces; j++)
if (i < depth - 2)
printf(" ");
else
printf("%c", 196);
}
printf(" %d\n", root->data);
for (int i = 0; i < depth; i++)
{
if (path[i])
printf("%c", 179);
else
printf(" ");
for (int j = 1; j < spaces; j++)
printf(" ");
}
rbt_display_treeview(root->left, depth, path, false);
}
上面的代码称为:
// Red-Black tree is created and elements (int) are added
// Printing the tree
char *path = calloc(10000, sizeof(char));
if (!path)
return;
rbt_display_treeview(tree->root, 0, path, false);
printf("\n");
free(path);
但是有两个问题:当节点是根节点时,此代码将尝试访问-1
的索引char *path
,如果树确实是树,则可能会发生char *path
的溢出真的很大。所以这是我的前两个问题:
path
应该有多大,以便如果用户尝试打印一棵真正的大树,他将在缓冲区溢出之前耗尽堆栈空间? 测试时,我在红黑树中按顺序添加了以下整数:
[ 16, -34, 24, 43, 18, 20, 22, -21, 4, 28, 45, 24, -47, -43, 29, 14, -35, 32, 8, -9, -46, 41, 46, -3, 17, -32, 24, 50, -19, -48, 15, 20, 22, -50, -43, 18, -28, 12, -14, 19, 12, 44, 19, 23, 45, -38, 45, -15, -28, 15, 35, 16, -41, -25, 7, -20, -7, -13, -31, -5, -48, -37, -23, -36 ]
它产生了以下输出:
┌─────── 50
│
┌─────── 46
│ │
│ └─────── 45
│ │
│ └─────── 44
│
┌─────── 43
│ │
│ │ ┌─────── 41
│ │ │
│ └─────── 35
│ │
│ └─────── 32
│
┌─────── 29
│ │
│ │ ┌─────── 28
│ │ │
│ └─────── 24
│ │
│ │ ┌─────── 23
│ │ │
│ │ ┌─────── 22
│ │ │ │
│ └─────── 20
│ │
│ │ ┌─────── 19
│ │ │
│ └─────── 18
│ │
│ └─────── 17
│
16
│
│ ┌─────── 15
│ │
│ ┌─────── 14
│ │ │
│ │ └─────── 12
│ │
│ ┌─────── 8
│ │ │
│ │ │ ┌─────── 7
│ │ │ │
│ │ └─────── 4
│ │ │
│ ┌─────── -3
│ │ │
│ │ │ │ ┌─────── -5
│ │ │ │ │
│ │ │ ┌─────── -7
│ │ │ │ │
│ │ │ ┌─────── -9
│ │ │ │ │
│ │ │ │ └─────── -13
│ │ │ │ │
│ │ └─────── -14
│ │ │
│ │ │ ┌─────── -15
│ │ │ │ │
│ │ └─────── -19
│ │ │
│ │ └─────── -20
│ │ │
└─────── -21
│
│ ┌─────── -23
│ │
│ ┌─────── -25
│ │ │
│ ┌─────── -28
│ │ │
│ │ │ ┌─────── -31
│ │ │ │
│ │ └─────── -32
│ │ │
│ ┌─────── -34
│ │ │
│ │ │ ┌─────── -35
│ │ │ │
│ │ │ ┌─────── -36
│ │ │ │ │
│ │ │ │ └─────── -37
│ │ │ │
│ │ └─────── -38
│ │ │
│ │ └─────── -41
│ │
└─────── -43
│
│ ┌─────── -46
│ │
└─────── -47
│
└─────── -48
│
└─────── -50
但是随后我看到了一些不应该打印的行,例如数字22、4,-7,-13,-15等下方的行。因此,我在最后一个for
中添加了另一个条件循环查看是否可以过滤那些不必要的行:
for (int i = 0; i < depth; i++)
{
if (path[i] && (root->left || i != depth -1)) /* Here */
printf("%c", 179);
else
printf(" ");
for (int j = 1; j < spaces; j++)
printf(" ");
}
事实上确实如此,但是我仍然不知道为什么。同样,当节点-9
上方的两行不应出现时,它们仍在打印。这是我到目前为止的内容:
┌─────── 50
│
┌─────── 46
│ │
│ └─────── 45
│ │
│ └─────── 44
│
┌─────── 43
│ │
│ │ ┌─────── 41
│ │ │
│ └─────── 35
│ │
│ └─────── 32
│
┌─────── 29
│ │
│ │ ┌─────── 28
│ │ │
│ └─────── 24
│ │
│ │ ┌─────── 23
│ │ │
│ │ ┌─────── 22
│ │ │
│ └─────── 20
│ │
│ │ ┌─────── 19
│ │ │
│ └─────── 18
│ │
│ └─────── 17
│
16
│
│ ┌─────── 15
│ │
│ ┌─────── 14
│ │ │
│ │ └─────── 12
│ │
│ ┌─────── 8
│ │ │
│ │ │ ┌─────── 7
│ │ │ │
│ │ └─────── 4
│ │
│ ┌─────── -3
│ │ │
│ │ │ │ ┌─────── -5
│ │ │ │ │
│ │ │ ┌─────── -7
│ │ │ │
│ │ │ ┌─────── -9
│ │ │ │ │
│ │ │ │ └─────── -13
│ │ │ │
│ │ └─────── -14
│ │ │
│ │ │ ┌─────── -15
│ │ │ │
│ │ └─────── -19
│ │ │
│ │ └─────── -20
│ │
└─────── -21
│
│ ┌─────── -23
│ │
│ ┌─────── -25
│ │
│ ┌─────── -28
│ │ │
│ │ │ ┌─────── -31
│ │ │ │
│ │ └─────── -32
│ │
│ ┌─────── -34
│ │ │
│ │ │ ┌─────── -35
│ │ │ │
│ │ │ ┌─────── -36
│ │ │ │ │
│ │ │ │ └─────── -37
│ │ │ │
│ │ └─────── -38
│ │ │
│ │ └─────── -41
│ │
└─────── -43
│
│ ┌─────── -46
│ │
└─────── -47
│
└─────── -48
│
└─────── -50
P.S .:红黑树实现的工作方式与其他任何红黑树一样。您也可以在其他二进制树中对此进行测试,因为我希望此代码在任何二进制树上运行。