-2

I made a similar post on here but I did not get any useful feedback. I thus tried to re-do my code a bit to see if that would lead to any decent results. So far my code compiles but yet does not print anything and I am not sure why.

I have an example in int main() that should give me a tree that looks like:

/* The constructed AVL Tree would be
        9
       /  \
      1    10
    /  \     \
   0    5     11
  /    /  \
 -1   2    6
*/

Here is my code:

#include <algorithm>
#include <iostream>
#include <memory>
#include <utility>
#include <stack>
#include <queue>

struct Node {
    int data;
    int height;
    std::unique_ptr<Node> left = nullptr;
    std::unique_ptr<Node> right = nullptr;

    Node(const int& x, const int& y, std::unique_ptr<Node>&& p = nullptr, std::unique_ptr<Node>&& q = nullptr) :
        data(x),
        height(y),
        left(std::move(p)),
        right(std::move(q)) {}

    Node(const int& data) : data(data) {}

};
std::unique_ptr<Node> root = nullptr;

int height(std::unique_ptr<Node>& root) {
    if (!root) return 0;
    return root->height;
}

void fixHeight(std::unique_ptr<Node>& root) {
    auto h1 = height(root->left);
    auto h2 = height(root->right);
    root->height = (h1 > h2 ? h1 : h2) + 1;
}

void rightRotate(std::unique_ptr<Node>& p) {
    std::unique_ptr<Node> q = std::move(p->left);
    p->left = std::move(q->right);
    q->right = std::move(p);
    fixHeight(p);
    fixHeight(q);
}

void leftRotate(std::unique_ptr<Node>& q) {
    std::unique_ptr<Node> p = std::move(q->left);
    q->right = std::move(p->left);
    p->left = std::move(q);
    fixHeight(q);
    fixHeight(p);
}

int heightDiff(std::unique_ptr<Node>& root) {
    if (!root) return 0;

    return height(root->left) - height(root->right);
}

void balance(std::unique_ptr<Node>& root) {
    fixHeight(root);
    if (heightDiff(root) == 2) {
        if (heightDiff(root->right) < 0)
            rightRotate(root->right);
        leftRotate(root);
    }

    if (heightDiff(root) == -2) {
        if (heightDiff(root->left) > 0)
            leftRotate(root->left);
        rightRotate(root);
    }
}

void insert(std::unique_ptr<Node>& root, const int& theData) {
    std::unique_ptr<Node> newNode = std::make_unique<Node>(theData);
    if (!root) {
        root = std::move(newNode);
        return;
    }

    if (theData < root->data)
        insert(root->left, theData);

    else
        insert(root->right, theData);

    balance(root);
}

auto findMin(std::unique_ptr<Node>& root) {
    while (root->left != nullptr) root = std::move(root->left);
    return root.get();
}

void deleteNode(std::unique_ptr<Node>& root, const int& theData) {
    // Step 1: Perform regular deletion for BST
    if (!root) return;
    else if (theData < root->data) deleteNode(root->left, theData);
    else if (theData > root->data) deleteNode(root->right, theData);

    else {
        // Case 1: No child
        if (root->left == nullptr && root->right == nullptr) {
            root = nullptr;
        }

        // Case 2: One child
        else if (root->left == nullptr) {
            root = std::move(root->left);
        }

        else if (root->right == nullptr) {
            root = std::move(root->right);
        }

        // Case 3: Two children
        else {
            auto temp = findMin(root->right);
            temp->data = root->data;
            deleteNode(root->right, temp->data);
        }
    }

    if (!root) return;

    // Step 2: Update height of the current node
    root->height = 1 + std::max(height(root->left), height(root->right));

    // Step 3: Get the balalce factor of the this node (to 
    // check whether this node became unbalanced)
    int balance = heightDiff(root);

    // If this node becomes unbalanced, then there are 4 cases

    // Left Left Case
    if (balance > 1 && heightDiff(root->left) >= 0)
        rightRotate(root);

    // Left Right Case
    if (balance > 1 && heightDiff(root->left) < 0) {
        leftRotate(root->left);
        rightRotate(root);
    }

    // Right Right Case
    if (balance < -1 && heightDiff(root->right) <= 0)
        leftRotate(root);

    // Right Left Case
    if (balance < -1 && heightDiff(root->right) > 0) {
        rightRotate(root->right);
        leftRotate(root);
    }
}

void inorderTraversal(std::unique_ptr<Node>& root) {
    if (!root) {
        inorderTraversal(root->left);
        std::cout << root->data << " ";
        inorderTraversal(root->right);
    }
}

void preorderTraversal(std::unique_ptr<Node>& root) {
    if (root != nullptr) {
        std::cout << root->data << " ";
        preorderTraversal(root->left);
        preorderTraversal(root->right);
    }
}

void postorderTraversal(std::unique_ptr<Node>& root) {
    if (root != nullptr) {
        postorderTraversal(root->left);
        postorderTraversal(root->right);
        std::cout << root->data << " ";
    }
}

void DFS(std::unique_ptr<Node>& root) {
    if (!root) return;

    std::stack<Node const *> s;
    s.push(root.get());

    while (!s.empty()) {
        auto p = s.top();
        s.pop();

        if (p->right != nullptr) s.push(p->right.get());
        if (p->left != nullptr) s.push(p->left.get());

        std::cout << p->data << " ";
    }
}

void BFS(std::unique_ptr<Node>& root) {
    if (!root) return;

    std::queue<Node const *> q;
    q.push(root.get());

    while (!q.empty()) {
        auto p = q.front();
        q.pop();

        if (p->left != nullptr) q.push(p->left.get());
        if (p->right != nullptr) q.push(p->right.get());

        std::cout << p->data << " ";
    }
}

bool exists(int d) {
    auto temp = root.get();
    while (temp != nullptr) {
        if (temp->data == d) {
            return true;
        }
        else {
            if (d > temp->data) {
                temp = temp->right.get();
            }
            else {
                temp = temp->left.get();
            }
        }
    }
    return false;
}

int main() {

    //        8
    //      /    \
    //    4       10
    //   / \     /  \
    //  2   6   9    12

    //insert(root, 8);
    //insert(root, 10);
    //insert(root, 4);
    //insert(root, 2);
    //insert(root, 6);
    //insert(root, 12);
    //insert(root, 9);


  /* Constructing tree given in the above figure */
    insert(root, 9);
    insert(root, 5);
    insert(root, 10);
    insert(root, 0);
    insert(root, 6);
    insert(root, 11);
    insert(root, -1);
    insert(root, 1);
    insert(root, 2);

    /* The constructed AVL Tree would be
            9
           /  \
          1    10
        /  \     \
       0    5     11
      /    /  \
     -1   2    6
    */

    printf("Preorder traversal of the constructed AVL "
        "tree is \n");
    preorderTraversal(root);

    //deleteNode(root, 10);

    /* The AVL Tree after deletion of 10
            1
           /  \
          0    9
        /     /  \
       -1    5     11
           /  \
          2    6
    */

    //printf("\nPreorder traversal after deletion of 10 \n");
    //preorderTraversal(root);

    /*inorderTraversal(root);
    std::cout << "\n";

    preorderTraversal(root);
    std::cout << "\n";

    postorderTraversal(root);
    std::cout << "\n";

    DFS(root);
    std::cout << "\n";

    BFS(root);
    std::cout << "\n";

    exists(4) ? std::cout << "Yes" << std::endl : std::cout << "No" << std::endl;*/


    std::cin.get();
}
  • Please provide a link (or URL) to that "similar post". Read also [how to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Basile Starynkevitch Sep 29 '18 at 05:36
  • @BasileStarynkevitch Done, see edit –  Sep 29 '18 at 05:36
  • I strongly recommend compiling with all warnings and debug info `g++ -Wall -Wextra -g` and using a recent [`gdb` debugger](https://sourceware.org/gdb/current/onlinedocs/gdb/). Don't expect us to do your homework. Debugging skills are an essential part of C++ programming – Basile Starynkevitch Sep 29 '18 at 05:38
  • @BasileStarynkevitch I know I am asking for help on debugging this as I have not practiced myself enough, could you please help me on this one? –  Sep 29 '18 at 05:50
  • No. I recommend using the `gdb` debugger, and I won't do that for you. I also recommend reading *carefully* some [*Introduction to Algorithms*](https://en.wikipedia.org/wiki/Introduction_to_Algorithms), and that takes months. StackOverflow is *not* a debug-my-code site. [AVL tree](https://en.wikipedia.org/wiki/AVL_tree)s are a difficult data structure (I studied it 30 years ago, and forgot the details; even for me, it is not trivial to re-implement them). You need to budget several weeks of efforts to debug your code – Basile Starynkevitch Sep 29 '18 at 05:56
  • @BasileStarynkevitch I understand I am a mathematician trying to become better at programming and I am currently reading cracking the coding interview and The Algorithm Design manual. I just started reading these a few weeks ago so I am new at these types of data structures. –  Sep 29 '18 at 05:58
  • @BasileStarynkevitch Should I just delete this question then? –  Sep 29 '18 at 05:58
  • 1
    I won't delete that question *now* (but perhaps later). You need to understand your bugs, understand in *details* all the invariants on AVL trees (I learned that 30 years ago, but forgot the details), and check that your code is following them by using a debugger. You'll find that something is wrong in your code (but you need to understand, with a debugger, the actual behavior of your own code) – Basile Starynkevitch Sep 29 '18 at 06:02
  • 1
    When coding in C++, using a debugger is not a luxury you may avoid. It is an essential tool. You also need to compile with all warnings, and improve your code to get none. I simply cannot understand why you don't use a debugger (and if there is some valid reason for that, you should explicit it in your question) – Basile Starynkevitch Sep 29 '18 at 06:07
  • In *addition* of a debugger and your GCC compiler with all warnings, you might even use static source code analyzers like [Clang-Analyser](http://clang-analyzer.llvm.org/) or even [Frama-Clang](https://frama-c.com/frama-clang.html). But there is [*No Silver Bullet*](https://en.wikipedia.org/wiki/No_Silver_Bullet), whatever tools you will use, you'll need weeks of efforts – Basile Starynkevitch Sep 29 '18 at 06:14
  • @BasileStarynkevitch Yes, unfortunately I do not have weeks. –  Sep 29 '18 at 06:15
  • I am sorry for you. I recommend using a debugger. With good luck, you might find your bug in only a few days. Otherwise, you have failed your project (and this happens *very* often in software development). But my belief is that *without* a debugger, you won't find your bug (and you should *not* expect us to find it). I still don't understand what forbids you to use a debugger. – Basile Starynkevitch Sep 29 '18 at 06:16
  • If you are a mathematician (I am not, but I have been trained in math, my Master degree -1985- was on applied mathematics and computer science; I was taught about [distributions](https://en.wikipedia.org/wiki/Distribution_(mathematics)), got a good score at exams on them, forgot everything about them since that time), you might be interested in [formal methods](https://en.wikipedia.org/wiki/Formal_methods). But even if you use them, you still should also use a debugger when coding in C++; and I know that formal methods are not a silver bullet... – Basile Starynkevitch Sep 29 '18 at 06:35
  • @BasileStarynkevitch Neat! thank you! –  Sep 29 '18 at 06:36
  • ... but I am working as a research engineer in a formal methods lab (the one making [Frama-C](http://frama-c.com/)....) of 40 persons. I am probably the most skeptical guy about formal methods in practice in that lab. They are *not* a sliver bullet! Common sense is still needed for software development – Basile Starynkevitch Sep 29 '18 at 06:38
  • However, could you explain to us (and to me), in a few sentences, why you are forbidden to use a debugger when coding in C++. I am very curious about that (since this is highly unusual). – Basile Starynkevitch Sep 29 '18 at 06:41
  • @BasileStarynkevitch To be honest, I have no idea where to begin and what to look for in the case of using a debugger. I never really debugged before formally besides commenting out code and running it line by line to see where my code goes astray. –  Sep 29 '18 at 06:43
  • 1
    My opinion is that you absolutely need to improve your practical skills and learn how to use a debugger. In practice, that is not very hard. http://norvig.com/21-days.html gives very useful insights on. the practical skills related to software development. I don't understand how you can assess the behavior of your program without any debugger. Please explain! – Basile Starynkevitch Sep 29 '18 at 06:44
  • Read also about [the law of leaky abstractions](https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/) – Basile Starynkevitch Sep 29 '18 at 06:46
  • @BasileStarynkevitch I have been able to get through it without using one dont really know what to explain –  Sep 29 '18 at 06:47
  • AVL trees algorithm are more complex than what can easily and completely fit in a human brain (yours, mines, every ones else...). Debugger can help to deal with such limitations, which still exist. Our (still prehistoric) brain is fit for hunting, not software development. That sad fact won't change in our lifetime (but that is why *I Basile* find software development so exciting). – Basile Starynkevitch Sep 29 '18 at 06:48
  • A more practical approach is to *trust* your C++ standard library (people implementing it are quite clever). Then you just could use some standard [container](https://en.cppreference.com/w/cpp/container) such as `std::map` or `std::set` which implements some kind of [self-balancing binary search tree](https://en.wikipedia.org/wiki/Self-balancing_binary_search_tree), perhaps AVL ones. – Basile Starynkevitch Sep 29 '18 at 07:11

1 Answers1

2

At the first place the insert() function will not work. Initially when the AVL tree is empty, root = nullptr. Every time it will return void without inserting any new node. It should look something like this.

void insert(std::unique_ptr<Node>& root, const int& theData) {
    if (!root) { 
        root.reset(new Node(theData,0));
    }
    else {
        if (theData < root->data)
            insert(root->left, theData);
        else
            insert(root->right, theData);
            balance(root);
    }
}

Output:

enter image description here

seccpur
  • 4,996
  • 2
  • 13
  • 21
  • I see, if you see the old post I made above I have an insert() function that was similar to deleteNode but it still didn't work for some reason. –  Sep 29 '18 at 06:35
  • 1
    Insert code reedited to add height parameter . preorderTraversal now prints correctly. – seccpur Sep 29 '18 at 06:39
  • It did not compile for me throws this: Exception thrown: read access violation. std::_Unique_ptr_base >::_Myptr(...) returned 0x8. –  Sep 29 '18 at 06:45
  • Yes, now it seems to work and comment out the insert(root, 2) why does it work now when I do that? –  Sep 29 '18 at 06:51
  • 1
    You need to fix some flaws in the balance. TODO? – seccpur Sep 29 '18 at 06:51