1

Update: I can't get "Balancing" to work, because I cannot get "doAVLBalance" to recognize the member functions "isBalanced()", "isRightHeavy()", "isLeftHeavy". And I don't know why! I tried Sash's example(3rd answer) exactly but I get "deceleration is incompatible" and I couldn't fix that...so I tried doing it my way...and it tells me those member functions don't exist, when they clearly do.

"Error: class "IntBinaryTree:TreeNode" has no member "isRightHeavy". I'm stuck after trying for the last 4 hours :(. Updated code below, help would be much appreciated!!

I'm creating a String based Binary Search Tree and need to make it a "Balanced" tree. How do I do this?* Help please!! Thanks in advance!

BinarySearchTree.cpp:

    bool IntBinaryTree::leftRotation(TreeNode *root)
    {
        //TreeNode *nodePtr = root;  // Can use nodePtr instead of root, better?
        // root, nodePtr, this->?

        if(NULL == root)
        {return NULL;}

        TreeNode *rightOfTheRoot = root->right;
        root->right = rightOfTheRoot->left;
        rightOfTheRoot->left = root;

        return rightOfTheRoot;
    }

    bool IntBinaryTree::rightRotation(TreeNode *root)
    {
        if(NULL == root)
        {return NULL;}
        TreeNode *leftOfTheRoot = root->left;
        root->left = leftOfTheRoot->right;
        leftOfTheRoot->right = root;

        return leftOfTheRoot;
    }

    bool IntBinaryTree::doAVLBalance(TreeNode *root)
    {


        if(NULL==root)
            {return NULL;}
        else if(root->isBalanced()) // Don't have "isBalanced"
            {return root;}

        root->left = doAVLBalance(root->left);
        root->right = doAVLBalance(root->right);

        getDepth(root); //Don't have this function yet

        if(root->isRightHeavy()) // Don't have "isRightHeavey"
        {
            if(root->right->isLeftheavey())
            {
                root->right = rightRotation(root->right);
            }
            root = leftRotation(root);
        }
        else if(root->isLeftheavey()) // Don't have "isLeftHeavey"
        {
            if(root->left->isRightHeavey())
            {
                root->left = leftRotation(root->left);
            }
            root = rightRotation(root);
        }
        return root;
    }

    void IntBinaryTree::insert(TreeNode *&nodePtr, TreeNode *&newNode)
    {
        if(nodePtr == NULL)
            nodePtr = newNode;                  //Insert node
        else if(newNode->value < nodePtr->value)
            insert(nodePtr->left, newNode);     //Search left branch
        else
            insert(nodePtr->right, newNode);    //search right branch
    }

//
// Displays the number of nodes in the Tree


int IntBinaryTree::numberNodes(TreeNode *root)
{
    TreeNode *nodePtr = root;

    if(root == NULL)
        return 0;

    int count = 1; // our actual node
    if(nodePtr->left !=NULL)
    { count += numberNodes(nodePtr->left);
    }
    if(nodePtr->right != NULL)
    {
        count += numberNodes(nodePtr->right);
    }
    return count;
} 

    // Insert member function

    void IntBinaryTree::insertNode(string num)
    {
        TreeNode *newNode; // Poitner to a new node.

        // Create a new node and store num in it.
        newNode = new TreeNode;
        newNode->value = num;
        newNode->left = newNode->right = NULL;

        //Insert the node.
        insert(root, newNode);
    }

    // More member functions, etc.

BinarySearchTree.h:

class IntBinaryTree
{
private:
    struct TreeNode
    {
        string value; // Value in the node
        TreeNode *left; // Pointer to left child node
        TreeNode *right; // Pointer to right child node
    };

    //Private Members Functions
    // Removed for shortness
    void displayInOrder(TreeNode *) const;


public:
    TreeNode *root;
    //Constructor
    IntBinaryTree()
        { root = NULL; }
    //Destructor
    ~IntBinaryTree()
        { destroySubTree(root); }

    // Binary tree Operations
    void insertNode(string);
    // Removed for shortness

    int numberNodes(TreeNode *root);
    //int balancedTree(string, int, int); // TreeBalanced

    bool leftRotation(TreeNode *root);
    bool rightRotation(TreeNode *root);
    bool doAVLBalance(TreeNode *root); // void doAVLBalance();
    bool isAVLBalanced();

    int calculateAndGetAVLBalanceFactor(TreeNode *root);

    int getAVLBalanceFactor()
    {
        TreeNode *nodePtr = root; // Okay to do this? instead of just
        // left->mDepth
        // right->mDepth

        int leftTreeDepth = (left !=NULL) ? nodePtr->left->Depth : -1;
        int rightTreeDepth = (right != NULL) ? nodePtr->right->Depth : -1;
        return(leftTreeDepth - rightTreeDepth);
    }

    bool isRightheavey() { return (getAVLBalanceFactor() <= -2); }

    bool isLeftheavey() { return (getAVLBalanceFactor() >= 2); }


    bool isBalanced()
    {
        int balanceFactor = getAVLBalanceFactor();
        return (balanceFactor >= -1 && balanceFactor <= 1);
    }


    int getDepth(TreeNode *root); // getDepth

    void displayInOrder() const
        { displayInOrder(root); }
    // Removed for shortness
};
Riotson
  • 81
  • 1
  • 7
  • 15

3 Answers3

1

There are many ways to do this, but I'd suggest that you actually not do this as all. If you want to store a BST of strings, there are much better options:

  1. Use a prewritten binary search tree class. The C++ std::set class offers the same time guarantees as a balanced binary search tree and is often implemented as such. It's substantially easier to use than rolling you own BST.

  2. Use a trie instead. The trie data structure is simpler and more efficient than a BST of strings, requires no balancing at all, and is faster than a BST.

If you really must write your own balanced BST, you have many options. Most BST implementations that use balancing are extremely complex and are not for the faint of heart. I'd suggest implementing either a treap or a splay tree, which are two balanced BST structures that are rather simple to implement. They're both more complex than the code you have above and I can't in this short space provide an implementation, but a Wikipedia search for these structures should give you plenty of advice on how to proceed.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • well the assignment states for us to "create" one so. But I'll look up that prewritten, would be good to see it! Yes I am seeing that, it's a bit difficult lol. I will look into those 2 when I get a chance, would be good to know, and I am not familiar with what a "trie" is. Seems there's a lot I should research and learn about Tree's. Thanks for all the info! I appreciate it. – Riotson Aug 03 '11 at 03:28
1

Unfortunately, we programmers are literal beasts.

make it a "Balanced" tree.

"Balanced" is context dependent. The introductory data structures classes typically refer to a tree being "balanced" when the difference between the node of greatest depth and the node of least depth is minimized. However, as mentioned by Sir Templatetypedef, a splay tree is considered a balancing tree. This is because it can balance trees rather well in cases that few nodes accessed together at one time frequently. This is because it takes less node traversals to get at the data in a splay tree than a conventional binary tree in these cases. On the other hand, its worst-case performance on an access-by-access basis can be as bad as a linked list.

Speaking of linked lists...

Because otherwise without the "Balancing" it's the same as a linked-list I read and defeats the purpose.

It can be as bad, but for randomized inserts it isn't. If you insert already-sorted data, most binary search tree implementations will store data like an bloated and ordered linked list. However, that's only because you're building one side of the tree continually. (Imagine inserting 1, 2, 3, 4, 5, 6, 7, etc... into a binary tree. Try it on paper and see what happens.)

If you have to balance in a theoretical worst-case-must-guaranteed sense, I recommend looking up red-black trees. (Google it, second link is pretty good.)

If you have to balance it in a reasonable way for this particular scenario, I'd go with integer indices and a decent hash function -- that way the balancing will happen probabilistically without any extra code. That is to say, make your comparison function look like hash(strA) < hash(strB) instead of what you've got now. (For a quick but effective hash for this case, look up FNV hashing. First hit on Google. Go down until you see useful code.) You can worry about the details of implementation efficiency if you want to. (For example, you don't have to perform both hashes every single time you compare since one of the strings never changes.)

If you can get away with it, I strongly recommend the latter if you're in a crunch for time and want something fast. Otherwise, red-black trees are worthwhile since they're extremely useful in practice when you need to roll your own height-balanced binary trees.

Finally, addressing your code above, see the comments in the code below:

int IntBinaryTree::numberNodes(TreeNode *root)
{
    if(root = NULL) // You're using '=' where you want '==' -- common mistake.
                    // Consider getting used to putting the value first -- that is,
                    // "NULL == root". That way if you make that mistake again, the
                    // compiler will error in many cases.
        return 0;
    /*
    if(TreeNode.left=null && TreeNode.right==null)  // Meant to use '==' again.
    { return 1; }

    return numberNodes(node.left) + numberNodes(node.right);
    */

    int count = 1; // our actual node
    if (left != NULL)
    {
        // You likely meant 'root.left' on the next line, not 'TreeNode.left'.
        count += numberNodes(TreeNode.left);
        // That's probably the line that's giving you the error.
    }
    if (right != NULL)
    {
        count += numberNodes(root.right);
    }
    return count;
}
Kaganar
  • 6,540
  • 2
  • 26
  • 59
  • thanks for the detailed explanation and the help!! Reading that hashing link on google now. Fixed everything you mentioned in the code (Re-posted the new code in my post) and it works now! :) Except...how do I call it in main? I can't figure it out. Also another question, should I use "if(nodePtr->left !=NULL)" or "if(left !=NULL)"??? It doesn't say either is wrong (Then again I haven't been able to call the function yet so). – Riotson Aug 03 '11 at 03:23
  • Sorry, there were some obvious errors I failed to observe. TreeNode is the name of the class, so you mean root->left instead of TreeNode.left. Likewise, root.right doesn't work since root is a pointer, so you mean root->right. Also, during your if() checks you mean root->left and root->right instead of left/right. (I suspect you've already fixed these due to the fact that you'll get compiler errors for most of them if you don't.) – Kaganar Aug 03 '11 at 04:17
  • Yes I did! Thanks to your help! And thanks for the explanation. Only thing left I don't understand is, how do I call this function in main? tree.numberNodes(); ....says too few arguments, but I can't figure out what to pass to it. – Riotson Aug 03 '11 at 05:34
  • The numberNodes function as defined takes one argument. You probably want to start it with the root node of the tree. However, to create a clean abstracted class, you don't want anyone to be able to do this. What you really want is to rename your numberNodes function to something like 'numberNodesInternal' and change all your current calls to 'numberNodesInternal'. Then make a new numberNodes function that calls numberNodesInternal(root). – Kaganar Aug 03 '11 at 07:20
  • Thanks! Couldn't have done it with out your help! :D Only problem now is getting it to recognize those functions in the balancing! If it's not too much trouble could you read my updated post/code please? I'm completely stuck, if I can just get it to recognize those, I think I'm finally finished! Also, when a post is a few days old, it moves further back in line on the "questions" list, right? – Riotson Aug 04 '11 at 05:20
  • I'd love to help more, but unfortunately I'm out of time for a while. Sorry, but good luck! – Kaganar Aug 04 '11 at 06:08
1

Programmers use AVL Tree concepts to balance binary trees. It is quite simple. More information can be found online. Quick wiki link

Below is the sample code which does tree balance using AVL algorithm.

Node *BinarySearchTree::leftRotation(Node *root)
{
    if(NULL == root)
    {
        return NULL;
    }
    Node *rightOfTheRoot = root->mRight;
    root->mRight = rightOfTheRoot->mLeft;
    rightOfTheRoot->mLeft = root;

    return rightOfTheRoot;
}

Node *BinarySearchTree::rightRotation(Node *root)
{
    if(NULL == root)
    {
        return NULL;
    }
    Node *leftOfTheRoot = root->mLeft;
    root->mLeft = leftOfTheRoot->mRight;
    leftOfTheRoot->mRight = root;

    return leftOfTheRoot;
}

Node *BinarySearchTree::doAVLBalance(Node *root)
{
    if(NULL == root)
    {
        return NULL;
    }
    else if(root->isBalanced())
    {
        return root;
    }

    root->mLeft  = doAVLBalance(root->mLeft);
    root->mRight = doAVLBalance(root->mRight);

    getDepth(root);

    if(root->isRightHeavy())
    {
        if(root->mRight->isLeftHeavy())
        {
            root->mRight = rightRotation(root->mRight);
        }
        root = leftRotation(root);
    }
    else if(root->isLeftHeavy())
    {
        if(root->mLeft->isRightHeavy())
        {
            root->mLeft = leftRotation(root->mLeft);
        }
        root = rightRotation(root);
    }

    return root;
}

Class Definition

class BinarySearchTree
{
public:
    // .. lots of methods 
    Node *getRoot();
    int getDepth(Node *root);

    bool isAVLBalanced();
    int calculateAndGetAVLBalanceFactor(Node *root);
    void doAVLBalance();

private:
     Node *mRoot;
};

class Node
{
public:
    int  mData;
    Node *mLeft;
    Node *mRight;
    bool mHasVisited;
    int mDepth;
public:

    Node(int data)
    : mData(data),
      mLeft(NULL),
      mRight(NULL),
      mHasVisited(false),
      mDepth(0)
    {
    }

    int getData()              { return mData; }

    void setData(int data)     { mData = data;  }

    void setRight(Node *right) { mRight = right;}

    void setLeft(Node *left)   { mLeft = left; }

    Node * getRight()          { return mRight; }

    Node * getLeft()           { return mLeft; }

    bool hasLeft()             { return (mLeft != NULL);  }

    bool hasRight()            { return (mRight != NULL); }

    bool isVisited()           { return (mHasVisited == true); }

    int getAVLBalanceFactor()
    {
        int leftTreeDepth = (mLeft != NULL) ? mLeft->mDepth : -1;
        int rightTreeDepth = (mRight != NULL) ? mRight->mDepth : -1;
        return(leftTreeDepth - rightTreeDepth);
    }

    bool isRightHeavy() { return (getAVLBalanceFactor() <= -2); }

    bool isLeftHeavy()  { return (getAVLBalanceFactor() >= 2);  }

    bool isBalanced()
    {
        int balanceFactor = getAVLBalanceFactor();
        return (balanceFactor >= -1 && balanceFactor <= 1);
    }
};
Shash316
  • 2,218
  • 18
  • 19
  • thank you for that sample code!! Wrote my code according to that (Updated original post). Though I'm a little confused, why is it type "Node"? I tried that with mine ("TreeNode") but it wouldn't accept it...so I made it into an int. But now it doesn't want to accept the returns "Error: return value type does not match the function type". Besides that everything else is okay. I just don't know what type to write it as. – Riotson Aug 03 '11 at 03:31
  • No matter how much I tried I couldn't get your sample code to work, I kept getting an "Incompatible" error, I tried changing things several times/doing it different ways, even my way, but I still cannot get the "Balancing" to work 100% :(. Updated my post...if you could help please, would be much appreciated!! – Riotson Aug 04 '11 at 05:06