[英]How can I print a binary tree?
我正在尝试从这样的代码打印出一个二叉树图,例如:
4
/ \
2 6
/ \ / \
1 3 5 7
我尝试研究如何在整个互联网上打印一个,但答案要么令人困惑,要么根本没有太大帮助。 我尝试通过使用类似于 U 为我的插入函数所做的递归来制作打印函数,但它只是将每个音符中的所有数字打印在一条垂直直线上。 顺序是根,左左,左右,右左,右右。 另外,当您输入数字 0 时,循环会停止为树输入数字。
#include <stdio.h>
#include <stdlib.h>
//typedef char* string;
typedef struct node{
int num;
struct node* left;
struct node* right;
}
node;
void print(node* pp){
printf("%i\n",pp->num);
if(pp->left !=NULL){
print(pp->left);
}
if(pp->right !=NULL){
print(pp->right);
}
}
void insert(int y, node* p){
if (p->num > y){
if (p->left == NULL){
node* a = malloc(sizeof(node));
p->left = a;
p->left->num = y;
}
else{
insert(y, p->left);
}
}
if (p->num < y){
if (p->right == NULL){
node* a = malloc(sizeof(node));
p->right = a;
p->right->num = y;
}
else{
insert(y, p->right);
}
}
}
int main(void) {
printf("Hello World\n");
node *n = malloc(sizeof(node));
printf("In put root number: ");
int x = 0;
scanf("%i", &x);
printf("\n");
n->num = x;
int y = 1;
while (y != 0){
printf("In put number: ");
scanf("%i", &y);
//printf("\n");
insert(y, n);
}
print(n);
return 0;
}
您无法在发布样本时打印树,因为打印设备从左到右,然后从上到下,因此您需要逐层打印树,而不是按前序、中序或后序导航树.
如果您改为这样打印,您可以获得一些令人满意的结果:
+-7
+-6
| +-5
+-4
| +-3
+-2
+-1
但这仍然是一个挑战。 继续进行的最佳方法是使用例程打印右子树,类似于
+---------------+
+-| right subtree |
| +---------------+
另一个打印节点:
+-node
另一个打印左子树:
| +--------------+
+-| left subtree |
+--------------+
并将它们称为适当的,按此顺序打印树的各个部分。
重要的一件事是leftSubTree()
和rightSubTree()
需要一个前缀作为参数传递才能绘制正确的树结构,这在上面绘制的框之外失败,因此节点之间的链接被正确绘制。 例如,左子树需要绘制与为父节点绘制的前缀相同的前缀,然后是|
在我们到达子树的根节点之前,然后是一个+-
和根节点,然后是一个由两个空格组成的字符串,为树的未显示部分腾出空间。 rightSubtree()
将首先打印空部分,然后是根节点,最后是|
部分。
就目前而言,并且将问题视为学术问题,我会让您自行思考并为这种方法自己思考解决方案。 垂直树从上到下和从左到右的顺序打印要复杂得多。
让我们研究右子树,如上所示。 有一个框表示右子树应该打印的内容,并且有一个前缀,其中一部分是针对整个树固定的,另一部分是我们尝试打印的级别的变量,我将在下面尝试区分它们:
+----------fixed part
| +---variable part
v v v right subtree
+--------+----+--------------------------+
| | | |
| | +-Root Node of Right subtree |
| | | | |
| | | +--------------------------+
| --Root Node
| | | +--------------------------+
| | | | |
| | | | |
| | | | |
| | | | |
| | +-Root Node of Left Subtree |
| | | |
+--------+----+--------------------------+
如您所见,中间前缀在根节点之前和之后绘制不同(第一部分在右子树的根节点之前有空白并在该节点之后填充一行,第二部分,在根节点之后左子树根节点的根节点和之后的空白)我们将做三个例程,一个是绘制节点本身,一个是左子树和右子树,用于绘制左右两侧的完整子树。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int key;
struct node *left;
struct node *right;
};
char buffer[1024];
/* prints a node, with its key and prefix. */
static void print_node(
struct node *n, /* node to print */
FILE *o) /* file to print to */
{
/* the first string is the fixed part that prefix the whole
* subtree, the second is the node's name. */
fprintf(o, "%s+-%d\n", buffer, n->key);
}
/* prints a subtree (the first one in the sequence)
* printing a left or right subtree is controlled by the
* prf_right and prf_left parameters passed to the call. */
static void print_subtree(
struct node *n, /* root node reference */
FILE *o, /* FILE descriptor to use as output. */
const char *prf_right, /* right prefix */
const char *prf_left, /* left prefix */
char *buf, int buf_sz) /* buffer management, to add prefixes to */
{
if (n->right) { /* right subtree */
/* add the prefix for the right subtree, this is prf_right for
* the right part (the first, before the root node) */
int res = snprintf(buf, buf_sz, "%s", prf_right);
print_subtree(n->right, o, " ", "| ", buf + res, buf_sz - res);
*buf = '\0';
}
print_node(n, o);
if (n->left) { /* left subtree */
/* add the prefix for the left subtree, this is prf_left
* for the left part (the second, after the root node) */
int res = snprintf(buf, buf_sz, "%s", prf_left);
print_subtree(n->left, o, "| ", " ", buf + res, buf_sz - res);
*buf = '\0';
}
}
int main()
{
struct node *root = NULL; /* empty tree */
/* while not EOF, read a line */
int key;
while (scanf("%d", &key) == 1) {
/* search for the pointer to be modified to add the node*/
struct node **parent = &root;
while (*parent != NULL) {
int res = key - (*parent)->key;
if (res == 0) {
printf("Node %d already in the tree, ignored\n",
key);
goto next_value;
} else if (res > 0) {
parent = &(*parent)->right;
} else {
parent = &(*parent)->left;
}
}
/* *parent == NULL */
*parent = malloc(sizeof **parent);
assert(*parent != NULL);
(*parent)->key = key;
(*parent)->left = (*parent)->right = NULL;
next_value: ;
}
/* now print a root tree (it has both prefixes equal to " ")
*/
print_subtree(root, stdout, " ", " ",
buffer, sizeof buffer);
}
主程序读取一个数字序列并将它们作为键插入到二叉树中,对于上面的示例树,产生它的有效序列应该是:
4 6 7 5 2 3 1
对于另一棵树:
$ btree
1 5 3 4 7 2
+-7
+-5
| | +-4
| +-3
| +-2
+-1
$ _
尝试这个 :
struct Tree
{
Tree * left, * right;
int element;
};
//This function prints the given level of the given tree, assuming
//that the node has the given x cordinate.
void print_level(asciinode *node, int x, int level)
{
int i, isleft;
if (node == NULL) return;
isleft = (node->parent_dir == -1);
if (level == 0)
{
for (i=0; i<(x-print_next-((node->lablen-isleft)/2)); i++)
{
printf(" ");
}
print_next += i;
printf("%s", node->label);
print_next += node->lablen;
}
else if (node->edge_length >= level)
{
if (node->left != NULL)
{
for (i=0; i<(x-print_next-(level)); i++)
{
printf(" ");
}
print_next += i;
printf("/");
print_next++;
}
if (node->right != NULL)
{
for (i=0; i<(x-print_next+(level)); i++)
{
printf(" ");
}
print_next += i;
printf("\\");
print_next++;
}
}
else
{
print_level(node->left,
x-node->edge_length-1,
level-node->edge_length-1);
print_level(node->right,
x+node->edge_length+1,
level-node->edge_length-1);
}
}
//This function fills in the edge_length and
//height fields of the specified tree
void compute_edge_lengths(asciinode *node)
{
int h, hmin, i, delta;
if (node == NULL) return;
compute_edge_lengths(node->left);
compute_edge_lengths(node->right);
/* first fill in the edge_length of node */
if (node->right == NULL && node->left == NULL)
{
node->edge_length = 0;
}
else
{
if (node->left != NULL)
{
for (i=0; i<node->left->height && i < MAX_HEIGHT; i++)
{
rprofile[i] = -INFINITY;
}
compute_rprofile(node->left, 0, 0);
hmin = node->left->height;
}
else
{
hmin = 0;
}
if (node->right != NULL)
{
for (i=0; i<node->right->height && i < MAX_HEIGHT; i++)
{
lprofile[i] = INFINITY;
}
compute_lprofile(node->right, 0, 0);
hmin = MIN(node->right->height, hmin);
}
else
{
hmin = 0;
}
delta = 4;
for (i=0; i<hmin; i++)
{
delta = MAX(delta, gap + 1 + rprofile[i] - lprofile[i]);
}
//If the node has two children of height 1, then we allow the
//two leaves to be within 1, instead of 2
if (((node->left != NULL && node->left->height == 1) ||
(node->right != NULL && node->right->height == 1))&&delta>4)
{
delta--;
}
node->edge_length = ((delta+1)/2) - 1;
}
//now fill in the height of node
h = 1;
if (node->left != NULL)
{
h = MAX(node->left->height + node->edge_length + 1, h);
}
if (node->right != NULL)
{
h = MAX(node->right->height + node->edge_length + 1, h);
}
node->height = h;
}
asciinode * build_ascii_tree_recursive(Tree * t)
{
asciinode * node;
if (t == NULL) return NULL;
node = malloc(sizeof(asciinode));
node->left = build_ascii_tree_recursive(t->left);
node->right = build_ascii_tree_recursive(t->right);
if (node->left != NULL)
{
node->left->parent_dir = -1;
}
if (node->right != NULL)
{
node->right->parent_dir = 1;
}
sprintf(node->label, "%d", t->element);
node->lablen = strlen(node->label);
return node;
}
//Copy the tree into the ascii node structre
asciinode * build_ascii_tree(Tree * t)
{
asciinode *node;
if (t == NULL) return NULL;
node = build_ascii_tree_recursive(t);
node->parent_dir = 0;
return node;
}
//Free all the nodes of the given tree
void free_ascii_tree(asciinode *node)
{
if (node == NULL) return;
free_ascii_tree(node->left);
free_ascii_tree(node->right);
free(node);
}
//The following function fills in the lprofile array for the given tree.
//It assumes that the center of the label of the root of this tree
//is located at a position (x,y). It assumes that the edge_length
//fields have been computed for this tree.
void compute_lprofile(asciinode *node, int x, int y)
{
int i, isleft;
if (node == NULL) return;
isleft = (node->parent_dir == -1);
lprofile[y] = MIN(lprofile[y], x-((node->lablen-isleft)/2));
if (node->left != NULL)
{
for (i=1; i <= node->edge_length && y+i < MAX_HEIGHT; i++)
{
lprofile[y+i] = MIN(lprofile[y+i], x-i);
}
}
compute_lprofile(node->left, x-node->edge_length-1, y+node->edge_length+1);
compute_lprofile(node->right, x+node->edge_length+1, y+node->edge_length+1);
}
void compute_rprofile(asciinode *node, int x, int y)
{
int i, notleft;
if (node == NULL) return;
notleft = (node->parent_dir != -1);
rprofile[y] = MAX(rprofile[y], x+((node->lablen-notleft)/2));
if (node->right != NULL)
{
for (i=1; i <= node->edge_length && y+i < MAX_HEIGHT; i++)
{
rprofile[y+i] = MAX(rprofile[y+i], x+i);
}
}
compute_rprofile(node->left, x-node->edge_length-1, y+node->edge_length+1);
compute_rprofile(node->right, x+node->edge_length+1, y+node->edge_length+1);
}
Here is the asciii tree structure…
struct asciinode_struct
{
asciinode * left, * right;
//length of the edge from this node to its children
int edge_length;
int height;
int lablen;
//-1=I am left, 0=I am root, 1=right
int parent_dir;
//max supported unit32 in dec, 10 digits max
char label[11];
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.