繁体   English   中英

如何打印二叉树?

[英]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()将首先打印空部分,然后是根节点,最后是| 部分。

就目前而言,并且将问题视为学术问题,我会让您自行思考并为这种方法自己思考解决方案。 垂直树从上到下和从左到右的顺序打印要复杂得多。

第2章

让我们研究右子树,如上所示。 有一个框表示右子树应该打印的内容,并且有一个前缀,其中一部分是针对整个树固定的,另一部分是我们尝试打印的级别的变量,我将在下面尝试区分它们:

    +----------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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM