C ++在控制台问题中绘制二叉树

时间:2014-01-15 02:52:53

标签: c++ tree binary-tree

我正在进行一项我需要创建二叉树的任务。我有二进制逻辑正确,但我很难知道如何以及在何处创建树。下面的屏幕截图是我当前的输出,我想将其制作成树的形式,其根部位于顶部并向下移动。在这一点上,如果横向更容易,我会在这一点上解决这个问题。

C++ binary tree current output

#include <iostream>
#include <string>

using namespace std;

class TreeNode
{
public:
   void insert_node(TreeNode* new_node);
   void print_nodes() const;
   bool find(string value) const;
private:
   string data;
   TreeNode* left;
   TreeNode* right;
friend class BinarySearchTree;
};

class BinarySearchTree
{
public:
   BinarySearchTree();
   void insert(string data);
   void erase(string data);
   int count(string data) const;
   void print() const;
private:
   TreeNode* root;
};

/*
    BinarySearchTree Default constructor
*/

BinarySearchTree::BinarySearchTree()
{  
   root = NULL;
}

void BinarySearchTree::print() const
{  
   if (root != NULL)
   {
      root->print_nodes();
   }
}

void BinarySearchTree::insert(string data)
{  
    // Creates a new node and sets values
   TreeNode* new_node = new TreeNode;
   // Saves data to new_node and pointers to NULL
   new_node->data = data;
   new_node->left = NULL;
   new_node->right = NULL;
   // sets root as node saved above
   if (root == NULL) 
   {
       root = new_node;
   }
    /*
        If root has has been set then determine how to link new_node.
        root is the parent node and new_node will be the child of root
    */
   else root->insert_node(new_node);
}

void TreeNode::insert_node(TreeNode* new_node)
{  
   // this-> referrs to root node
   if (new_node->data < this->data)
   {  
       // Sets left node of root to
      // point to new_node
      if (this->left == NULL) 
          {
              this->left = new_node;
          }
      // inserts a new node onto root->left
      else this->left->insert_node(new_node);
   }
   else if (this->data < new_node->data)
   {  
      if (this->right == NULL) 
          {
              // inserts a new node onto root->right
              this->right = new_node;  

           }
      else this->right->insert_node(new_node);
   }
}

int BinarySearchTree::count(string data) const
{
   if (root == NULL) return 0;
   else if (root->find(data)) return 1;
   else return 0;
}

void BinarySearchTree::erase(string data)
{
   // Find node to be removed

   TreeNode* to_be_removed = root;
   TreeNode* parent = NULL;
   bool found = false;
   while (!found && to_be_removed != NULL)
   {
      if (to_be_removed->data < data)
      {
         parent = to_be_removed;
         to_be_removed = to_be_removed->right;
      }
      else if (data < to_be_removed->data)
      {
         parent = to_be_removed;
         to_be_removed = to_be_removed->left;
      }
      else found = true;
   }

   if (!found) return;

   // to_be_removed contains data

   // If one of the children is empty, use the other

   if (to_be_removed->left == NULL || to_be_removed->right == NULL)
   {
      TreeNode* new_child;
      if (to_be_removed->left == NULL) 
         new_child = to_be_removed->right;
      else 
         new_child = to_be_removed->left;
       if (parent == NULL) // Found in root
         root = new_child;
      else if (parent->left == to_be_removed)
         parent->left = new_child;
      else 
         parent->right = new_child;
      return;
   }

   // Neither subtree is empty

   // Find smallest element of the right subtree

   TreeNode* smallest_parent = to_be_removed;
   TreeNode* smallest = to_be_removed->right;
   while (smallest->left != NULL)
   {
      smallest_parent = smallest;
      smallest = smallest->left;
   }

   // smallest contains smallest child in right subtree

   // Move contents, unlink child
   to_be_removed->data = smallest->data;
   if (smallest_parent == to_be_removed) 
      smallest_parent->right = smallest->right; 
   else 
      smallest_parent->left = smallest->right; 
}

bool TreeNode::find(string value) const
{
   if (value < data)
   {
      if (left == NULL) return false;
      else return left->find(value);
   }
   else if (data < value)
   {
      if (right == NULL) return false;
      else return right->find(value);
   }
   else 
      return true;
}

void TreeNode::print_nodes() const
{ 

   if (this->right != NULL)
   {
       cout << data << "\n" << "\\" << "\n"  <<  this->right->data << " " << "\n";
       this->right->print_nodes();


        if (this->left != NULL) 
        {
            cout <<  data << "\n" << "/" << "\n" << this->left->data << "\n";
            this->left->print_nodes();
        }
   }

}

int main()
{  
   BinarySearchTree t;
   t.insert("D");
   t.insert("B");
   t.insert("A");
   t.insert("C");
   t.insert("F");
   t.insert("E");
   t.insert("I");
   t.insert("G");
   t.insert("H");
   t.insert("J");

   t.print();

   cout << "\n \n";

   cout << "\n \n";

   system("pause");
   return 0;
}

2 个答案:

答案 0 :(得分:2)

没有给你完整的答案(毕竟这是一个作业)我可以指出你的一些参考和搜索术语。你想要完成的是递归很难。您可能更喜欢breadth first traversal

您基本上使用另一个容器在树中按级别从右到左添加节点。完成后,您将迭代第二个容器并打印值。由于您可以计算级别数,因此可以很容易地使用空格格式化输出以缩进左侧和右侧节点。

它也可以在一次遍历中完成(仍然使用第二个容器),但算法稍微复杂一些。

答案 1 :(得分:1)

有很多方法可以做到这一点。这是一个:

A
|-B
| |-C
| | |-H
| | `-I
| `-D
|   |-F
|   `-G
`-E

这里A有孩子B和E. B有C和D.等......

那么我们该如何解决这个问题呢?这是伪代码:

Let S = {} (an empty global set of integers)

procedure indent(level)
for i in [0..level) 
  if i \in S print "| "
  else print "  "

procedure tee(level)
indent(level)
print("|-")
S = S + { level }

procedure ell(level)
indent(level)
print("`-")
S = S - { level }

procedure print(node, level)
if node is null
  print("[null]" with newline) // only prints when 1 child is missing
else
  print(node label with newline)
  if node has any children
    tee(level)
    print(node.left, level + 1)
    ell(level)
    print(node.right, level + 1)

设置跟踪哪些列需要垂直条。每个“T恤”形状都会开始竖条。每个“椭圆”形状都在同一列中结束。

该集合可以是一个布尔值(字符)数组,最初通过设置为零而为空。其余的几乎是C的逐行转换。

我在31个节点的完整树上快速得到结果。

L0
|-L1
| |-L2
| | |-L3
| | | |-L4
| | | `-L5
| | `-L6
| |   |-L7
| |   `-L8
| `-L9
|   |-L10
|   | |-L11
|   | `-L12
|   `-L13
|     |-L14
|     `-L15
`-L16
  |-L17
  | |-L18
  | | |-L19
  | | `-L20
  | `-L21
  |   |-L22
  |   `-L23
  `-L24
    |-L25
    | |-L26
    | `-L27
    `-L28
      |-L29
      `-L30

对于普通观众来说,值得指出的是,这适用于带有子标签的N-ary树(例如编译器中的抽象语法树)。将子名称参数添加到elltee,并为除最后一个孩子之外的每个孩子调用tee,其中只剩下ell