简体   繁体   English

二叉树运算符重载和递归

[英]Binary Tree operator overloading and recursion

I was wondering how to overload the == operator for a binary tree to compare if two trees have identical data at same nodes. 我想知道如何为二叉树重载==运算符,以比较两棵树在相同节点上是否具有相同数据。 So far this is what I have: 到目前为止,这就是我所拥有的:


bool TreeType::operator==(const TreeType& otherTree) const
{
    if((root == NULL) && (otherTree.root == NULL))
        return true; //two null trees are equal
    else if((root != NULL) && (otherTree.root != NULL))
    {
        return((root->info == otherTree.root->info) &&
               //this part doesn't actually do anything recursively...
               //(root->left == otherTree.root->left) &&
               //(root->right == otherTree.root->right))
    }
    else
        return false; //one tree is null the other is not
}


//TREETYPE DECLARATIONS
struct TreeNode;
enum OrderType {PRE_ORDER, IN_ORDER, POST_ORDER};
class TreeType
{
public:
  TreeType();                     // constructor
 ~TreeType();                    // destructor
  TreeType(const TreeType& originalTree); 
  void operator=(const TreeType& originalTree);
  // copy constructor
  void MakeEmpty();
  bool IsEmpty() const;
  bool IsFull() const;
  int LengthIs() const; 
  void RetrieveItem(ItemType& item, bool& found);
  void InsertItem(ItemType item);
  void DeleteItem(ItemType item);
  void ResetTree(OrderType order); 
  void GetNextItem (ItemType& item, OrderType order, 
       bool& finished);
  void Print(std::ofstream& outFile) const;
  bool operator==(const TreeType&) const;
private:
  TreeNode* root;
  QueType preQue;
  QueType inQue;
  QueType postQue;
};


//DEFINITIONS
struct TreeNode
{
  ItemType info;
  TreeNode* left;
  TreeNode* right;
};

bool TreeType::IsFull() const
// Returns true if there is no room for another item 
//  on the free store; false otherwise.
{
  TreeNode* location;
  try
  {
    location = new TreeNode;
    delete location;
    return false;
  }
  catch(std::bad_alloc exception)
  {
    return true;
  }
}

bool TreeType::IsEmpty() const
// Returns true if the tree is empty; false otherwise.
{
  return root == NULL;
}

int CountNodes(TreeNode* tree);

int TreeType::LengthIs() const
// Calls recursive function CountNodes to count the 
// nodes in the tree.
{
  return CountNodes(root);
}


int CountNodes(TreeNode* tree)
// Post: returns the number of nodes in the tree.
{
  if (tree == NULL)
    return 0;
  else 
    return CountNodes(tree->left) + CountNodes(tree->right) + 1;
}

void Retrieve(TreeNode* tree, 
     ItemType& item, bool& found);

void TreeType::RetrieveItem(ItemType& item, bool& found)
// Calls recursive function Retrieve to search the tree for item.
{
  Retrieve(root, item, found);
}


void Retrieve(TreeNode* tree, 
     ItemType& item, bool& found)
// Recursively searches tree for item.
// Post: If there is an element someItem whose key matches item's,
//       found is true and item is set to a copy of someItem; 
//       otherwise found is false and item is unchanged.
{
  if (tree == NULL)
    found = false;                     // item is not found.
  else if (item info)      
    Retrieve(tree->left, item, found); // Search left subtree.
  else if (item > tree->info)
    Retrieve(tree->right, item, found);// Search right subtree.
  else
  {
    item = tree->info;                 // item is found.
    found = true;
   }
} 

void Insert(TreeNode*& tree, ItemType item);

void TreeType::InsertItem(ItemType item)
// Calls recursive function Insert to insert item into tree.
{
  Insert(root, item);
}


void Insert(TreeNode*& tree, ItemType item)
// Inserts item into tree.
// Post:  item is in tree; search property is maintained.
{
  if (tree == NULL)
  {// Insertion place found.
    tree = new TreeNode;
    tree->right = NULL;
    tree->left = NULL;
    tree->info = item;
  }
  else if (item info)
    Insert(tree->left, item);    // Insert in left subtree.
  else
    Insert(tree->right, item);   // Insert in right subtree.
} 
void DeleteNode(TreeNode*& tree);

void Delete(TreeNode*& tree, ItemType item);

void TreeType::DeleteItem(ItemType item)
// Calls recursive function Delete to delete item from tree.
{
  Delete(root, item);
}


void Delete(TreeNode*& tree, ItemType item)
// Deletes item from tree.
// Post:  item is not in tree.
{
  if (item info)
    Delete(tree->left, item);   // Look in left subtree.
  else if (item > tree->info)
    Delete(tree->right, item);  // Look in right subtree.
  else
    DeleteNode(tree);           // Node found; call DeleteNode.
}   

void GetPredecessor(TreeNode* tree, ItemType& data);

void DeleteNode(TreeNode*& tree)
// Deletes the node pointed to by tree.
// Post: The user's data in the node pointed to by tree is no 
//       longer in the tree.  If tree is a leaf node or has only 
//       non-NULL child pointer the node pointed to by tree is 
//       deleted; otherwise, the user's data is replaced by its 
//       logical predecessor and the predecessor's node is deleted.
{
  ItemType data;
  TreeNode* tempPtr;

  tempPtr = tree;
  if (tree->left == NULL)
  {
    tree = tree->right;
    delete tempPtr;
  }
  else if (tree->right == NULL)
  {
    tree = tree->left;
    delete tempPtr;
  }
  else
  {
    GetPredecessor(tree->left, data);
    tree->info = data;
    Delete(tree->left, data);  // Delete predecessor node.
  }
}

void GetPredecessor(TreeNode* tree, ItemType& data)
// Sets data to the info member of the right-most node in tree.
{
  while (tree->right != NULL)
    tree = tree->right;
  data = tree->info;
}

void PrintTree(TreeNode* tree, std::ofstream& outFile) 
// Prints info member of items in tree in sorted order on outFile.
{
  if (tree != NULL)
  {
    PrintTree(tree->left, outFile);   // Print left subtree.
    outFile info;
    PrintTree(tree->right, outFile);  // Print right subtree.
  }
}

void TreeType::Print(std::ofstream& outFile) const
// Calls recursive function Print to print items in the tree.
{
  PrintTree(root, outFile);
}

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

void Destroy(TreeNode*& tree);

TreeType::~TreeType()
// Calls recursive function Destroy to destroy the tree.
{
  Destroy(root);
}


void Destroy(TreeNode*& tree)
// Post: tree is empty; nodes have been deallocated.
{
  if (tree != NULL)
  {
    Destroy(tree->left);
    Destroy(tree->right);
    delete tree;
  }
}

void TreeType::MakeEmpty()
{
  Destroy(root);
  root = NULL;
}


void CopyTree(TreeNode*& copy, 
     const TreeNode* originalTree);

TreeType::TreeType(const TreeType& originalTree)
// Calls recursive function CopyTree to copy originalTree 
//  into root.
{
  CopyTree(root, originalTree.root);
}

void TreeType::operator= 
     (const TreeType& originalTree)
// Calls recursive function CopyTree to copy originalTree 
// into root.
{
  {
  if (&originalTree == this)
    return;             // Ignore assigning self to self
  Destroy(root);      // Deallocate existing tree nodes
  CopyTree(root, originalTree.root);
  }

}
void CopyTree(TreeNode*& copy, 
     const TreeNode* originalTree)
// Post: copy is the root of a tree that is a duplicate 
//       of originalTree.
{
  if (originalTree == NULL)
    copy = NULL;
  else
  {
    copy = new TreeNode;
    copy->info = originalTree->info;
    CopyTree(copy->left, originalTree->left);
    CopyTree(copy->right, originalTree->right);
  }
}
// Function prototypes for auxiliary functions.

void PreOrder(TreeNode*, QueType&);
// Enqueues tree items in preorder.


void InOrder(TreeNode*, QueType&);
// Enqueues tree items in inorder.


void PostOrder(TreeNode*, QueType&);
// Enqueues tree items in postorder.


void TreeType::ResetTree(OrderType order)
// Calls function to create a queue of the tree elements in 
// the desired order.
{
  switch (order)
  {
    case PRE_ORDER : PreOrder(root, preQue);
                     break;
    case IN_ORDER  : InOrder(root, inQue);
                     break;
    case POST_ORDER: PostOrder(root, postQue);
                     break;
  }
}


void PreOrder(TreeNode* tree, 
     QueType& preQue)
// Post: preQue contains the tree items in preorder.
{
  if (tree != NULL)
  {
    preQue.Enqueue(tree->info);
    PreOrder(tree->left, preQue);
    PreOrder(tree->right, preQue);
  }
}


void InOrder(TreeNode* tree, 
     QueType& inQue)
// Post: inQue contains the tree items in inorder.
{
  if (tree != NULL)
  {
    InOrder(tree->left, inQue);
    inQue.Enqueue(tree->info);
    InOrder(tree->right, inQue);
  }
}


void PostOrder(TreeNode* tree, 
     QueType& postQue)
// Post: postQue contains the tree items in postorder.
{
  if (tree != NULL)
  {
    PostOrder(tree->left, postQue);
    PostOrder(tree->right, postQue);
    postQue.Enqueue(tree->info);
  }
}


void TreeType::GetNextItem(ItemType& item, 
     OrderType order, bool& finished)
// Returns the next item in the desired order.
// Post: For the desired order, item is the next item in the queue.
//       If item is the last one in the queue, finished is true; 
//       otherwise finished is false.
{
  finished = false;
  switch (order)
  {
    case PRE_ORDER  : preQue.Dequeue(item);
                      if (preQue.IsEmpty())
                        finished = true;
                      break;
    case IN_ORDER   : inQue.Dequeue(item);
                      if (inQue.IsEmpty())
                        finished = true;
                      break;
    case  POST_ORDER: postQue.Dequeue(item);
                      if (postQue.IsEmpty())
                        finished = true;
                      break;
  }
}

I have a similar function that takes two TreeNode pointers as parameters but I've been stuck on how to convert it to this function. 我有一个类似的函数,它需要两个TreeNode指针作为参数,但是我一直在坚持将其转换为该函数的方法。

The definition of tree is from a book. 树的定义来自一本书。 I'm just supposed to add the functionality of an overloaded == operator. 我只是应该添加重载==运算符的功能。

It would probably be easiest to add equality operator to the node class. 将相等运算符添加到node类可能是最简单的。

struct node
{
    int info;
    node * left;
    node * right;

    friend bool operator==(node const & lhs, node const & rhs)
    {
        return lhs.info == rhs.info
            && ((lhs.left == 0 && rhs.left == 0)
                || (lhs.left != 0 && rhs.left != 0 && *lhs.left == *rhs.left))
            && ((lhs.right == 0 && rhs.right == 0)
                || (lhs.right != 0 && rhs.right != 0 && *lhs.right == *rhs.right));
    }
};

Then you can simply compare root nodes from TreeType::operator== . 然后,您可以简单地从TreeType::operator==比较根节点。

bool TreeType::operator==(const TreeType& otherTree) const
{
    return (root == 0 && otherTree.root == 0)
        || (root != 0 && otherTree.root != 0 && *root == *otherTree.root);
}
//value is an integer not an object so that will give you syntax errors.
//This is a more correct way to write this
bool TreeNode::operator==(const TreeNode& node)
{
     if (&node == this) return true;
     if (left != NULL)
     {
         if (node.left != NULL) if (*left != *node.left) return false;
         else return false;
     }
     else if (node.left != NULL) return false;
     if (right != NULL)
     {
         if (node.right != NULL) if (*right != *node.right) return false;
         else return false;
     }
     else if (node.right != NULL) return false;
     return (value == node.value);
}

Generally the idea in these cases is to have a data structure which is a tree consisting of trees and leaf nodes. 通常,在这些情况下的想法是具有一个数据结构,该数据结构是由树和叶节点组成的树。 Something like 就像是

struct TreeType
{
    std::vector<TreeType> subtrees;
    std::vector<LeafNodes> leafs;
}

This allows one to define a == operator along the lines of 这允许人们定义==沿着线操作者

bool TreeType::operator==(const TreeType& rhs) const
{
    if each subtree == subtree && each leaf == leaf
    then true
    else false
}

Here the subtree comparison will call the == operator recursively on the children trees. 在这里, subtree比较将在子树上递归调用==运算符。

EDIT: It would be handy if you provided the exact organization of your TreeType data structure to allow for a better/specific answer. 编辑:如果您提供TreeType数据结构的确切组织以允许更好/特定的答案,那将很方便。

Given this class: 给定此类:

class TreeNode
{
  TreeNode* left;
  TreeNode* right;
  int value;

  bool operator==(const TreeNode& node);
};

I would write the == operator like this: 我会这样写==运算符:

bool TreeNode::operator==(const TreeNode& node)
{
  // Are we comparing the node to itself ?
  if (&node == this)
    return true;

  // We have a left node
  if (left != NULL)
  {
     // Does node have a left node too ?
     if (value.left != NULL)
     {
       // Are they different ?
       if (!(*left == *value.left))
         return false;
     } else
       // Node has no left node
       return false;
  } else
  {
    // We don't have a left node, does node have one ?
    if (value.left != NULL)
      return false;
  }

  // We have a right node
  if (right != NULL)
  {
     // Does node have a right node too ?
     if (value.right != NULL)
     {
       // Are they different ?
       if (!(*right == *value.right))
         return false;
     } else
       // Node has no right node
       return false;
  } else
  {
    // We don't have a right node, does node have one ?
    if (value.right != NULL)
      return false;
  }

  // Return true only if we have the same value.
  return (value == node.value);
}

Of course the recursion "end-conditions" can be switched for the algorithm to be optimized (checking the value s first might be more efficient). 当然,可以切换递归“结束条件”以优化算法(首先检查value s可能更有效)。

This is left to you as an exercise :D 这留给您作为练习:D

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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