【问题标题】:Self Balancing AVL Tree memory leaks自平衡 AVL 树内存泄漏
【发布时间】:2014-04-03 16:38:23
【问题描述】:

所以我一直在研究这个自平衡 AVL 树,我觉得它工作正常,但是有一些内存泄漏。我已经搜索并经历了一百万次,感觉就像试图弄清楚我做错了什么,但我对整个内存泄漏的事情还是新手,显然需要了解更多。如果有人可以帮助我或者可以看到泄漏的位置可能很棒,这里是我的 AVL 树的代码:

#pragma once
#include <algorithm>
#include <fstream>
#include "LinkedList.h"

template <typename ItemType>

class AVLTreeSet {

private:

  struct Node {
    ItemType info;
    Node* left;
    Node* right;
    int height;
  };

  Node* root;
  int size;

public:
    AVLTreeSet()
    {
        root = NULL;
        size = 0;
    }

    ~AVLTreeSet()
    {
        clear();
    }
    void clear()
    {
        Node* n = root;
        if(n != NULL)
        {
            clearTree(n->left);  
            clearTree(n->right); 
            delete n;
        }
        root = NULL;
    }
    void clearTree(Node* n)
    {
        if(n != NULL)
        {
            clearTree(n->left);   
            clearTree(n->right);  
            delete n;        
        }

    }

    void print(std::ofstream &out)
    {
        //cout << "HERE" << endl;
        LinkedList<Node*> list;
        int level = 0;
        int levelSize;
        int count = 0;
        Node* n = root;
        if (n == NULL)
        {
            return;
        }
        list.insert(n);
        levelSize = list.getSize();
        while(list.getSize() != 0)
        {
            count = 0;
            out << "level " << level << ": ";
            for (unsigned i = levelSize; i > 0; i--)
            {
                count++;
                if (count > 8)
                {
                    out << std::endl;
                    out << "level " << level << ": ";
                    count = 0;
                }
                n = list.getInfo();
                out <<n->info << "(" << getHeight(n) << ") ";
                if (n->left != NULL)
                {
                    //cout << "left is not null" << endl;
                    list.insert(n->left);
                }
                if (n->right != NULL)
                {
                    list.insert(n->right);
                    //cout << "right is not null" << endl;          
                }
                list.remove();

            }

            levelSize = list.getSize();
            level++;
            out << std::endl;
            //levelSize = list.getSize();
        }
    }
    void insert(const ItemType& item) 
    {
        //cout << "Insert FUNCTION" << endl;
        Node* current = root;

        if (current == NULL)
        { 
            //cout << "ADD FUNCTION NULL" << endl;
            current = new Node;
            current->info = item;
            current->left = NULL;
            current->right = NULL;
            current->height = 0;
            root = current;
            size++;
            //cout << current->info << endl;
            //cout << current->height << endl;
            return;
        }
        if (current->info > item)
        {
            current->left = add(item, current->left);
        }
        if (current->info < item)
        {
            current->right = add(item, current->right);
        }
        current = balance(current);
        root = current;

    }
    Node* add(const ItemType& item, Node* current) 
    {
        if (current == NULL)
        {
            current = new Node;
            current->info = item;
            current->left = NULL;
            current->right = NULL;
            current->height = 0;
            size++;
        }

        if (current->info > item)
        {
            current->left = add(item, current->left);
        }
        if (current->info < item)
        {
            current->right = add(item, current->right);
        }
        return current;
    }
    void remove(const ItemType& item)
    {
        Node* current = root;
        if (current == NULL)
        {
            //cout << "NULL" << endl;
            return;
        }
        if (current->info == item)
        {
            //cout << "FOUND" << endl;
            current = removeNext(item, current);
            current = balance(current);
            root = current;
            return;
        }
        if (current->info > item)
        {
            //cout << "LEFT" << endl;
            current->left = removeNext(item, current->left);
            if (current == root)
            {
                root = balance(current);
            }
            return;
        }
        if (current->info < item)
        {
            //cout << "RIGHT" << endl;
            current->right = removeNext(item, current->right);
            if (current == root)
            {
                root = balance(current);
            }
            return;
        }
    }
    Node* removeNext(const ItemType& item, Node* current)
    {
        Node* temp;
        if (current != NULL)
        {
        if (current->info > item)
        {
            //cout << "REMOVENEXT LEFT" << endl;
            current->left = removeNext(item, current->left);
            return current;
        }
        if (current->info < item)
        {
            //cout << "REMOVENEXT RIGHT" << endl;
            current->right = removeNext(item, current->right);
            return current;
        }
            //cout << "FOUND" << endl;
            if (current->left != NULL && current->right != NULL)
            {
                //cout << "LEFT AND RIGHT CHILDREN" << endl;
                temp = current;
                current = CTR(current->right);
                current->left = temp->left;
                //cout << current->info << endl;
                //looker = removeNext(current->info, temp->right);
                delete temp;
                size--;
                current = balance(current);
                return current;
            }
            else if (current->right != NULL)
            {
                //cout << "RIGHT ONE CHILD" << endl;
                temp = current;
                current = current->right;
                delete temp;
                size--;
                current = balance(current);
                return current;
            }
            else if (current->left != NULL)
            {
                //cout << "LEFT ONE CHILD" << endl;
                temp = current;
                current = current->left;
                delete temp;
                size--;
                current = balance(current);
                return current;
            }
            //cout << "CURRENT NODE" << endl;
            delete current;
            size--;
            return NULL;
        }
        //cout << "NOT FOUND" << endl;
        return current;
    }
    Node* CTR(Node* current)
    {
        while(current->left != NULL)
        {
            //cout << "ENTERED LOOP" << endl;
            current = current->left;
        }
        //cout << current->info << endl;
        return current;

    }
    bool find(const ItemType& item) 
    {
        Node* current = root;
        bool find = false;
        if (current == NULL)
        {
            return find;
        }
        if (item == current->info)
        {
            find = true;
            return find;
        }
        if (current->info > item && current->left != NULL)
        {
            find = findLeft(item, current->left);
        }
        if (current->info < item && current->right != NULL)
        {
            find = findRight(item, current->right);
        }
        return find;
    }
    bool findLeft(const ItemType& item, Node* current)
    {
        bool find = false;
        if (item == current->info)
        {
            find = true;
            return find;
        }
        if (current->info > item && current->left != NULL)
        {
            find = findLeft(item, current->left);
        }
        if (current->info < item && current->right != NULL)
        {
            find = findRight(item, current->right);
        }
        return find;
    }
    bool findRight(const ItemType& item, Node* current)
    {
        bool find = false;
        if (item == current->info)
        {
            find = true;
            return find;
        }
        if (current->info > item && current->left != NULL)
        {
            find = findLeft(item, current->left);
        }
        if (current->info < item && current->right != NULL)
        {
            find = findRight(item, current->right);
        }
        return find;
    }
    int getHeight(Node* temp)
    {
        int h = 0;
        if (temp != NULL)
        {
            int l_height = getHeight(temp->left);
            int r_height = getHeight(temp->right);
            int max_height = std::max(l_height, r_height);
            h = max_height + 1;
        }
        return h;
    }
    void setHeight(Node* n)
    {
        n->height = std::max(getHeight(n->right), getHeight(n->left)) + 1;
    }

    Node* balance(Node* n)
    {
        if (size == 1)
        {
            return n;
        }
        else if(getHeight(n->left) - getHeight(n->right) > 1) //n is out of balance 
        {   
            //cout << "BALANCE RIGHT" << endl;
            n = balanceToRight(n);
        }
        else if(getHeight(n->right) - getHeight(n->left) > 1)
        {
            //cout << "BALANCE LEFT" << endl;
            n = balanceToLeft(n);
        }   
            return n;
    }
    Node* balanceToRight(Node* n)
    {
        if(getHeight(n->left->right) > getHeight(n->left->left))
            {
                n->left = rotateLeft(n->left); //<--- extra step for double rotate
            }
            n = rotateRight(n); //<--- this is for single
        return n;
    }
    Node* balanceToLeft(Node* n)
    {
        if(getHeight(n->right->left) > getHeight(n->right->right))
            {
                n->right = rotateRight(n->right); //<--- extra step for double rotate
            }
            n = rotateLeft(n); //<--- this is for single
        return n;
    }
    Node* rotateRight(Node* n)
    {
        Node* temp = n->left;
        n->left = temp->right;
        temp->right = n;
        setHeight(n); //<--- set first
        setHeight(temp);
        return temp;
    }
    Node* rotateLeft(Node* n)
    {
        Node* temp = n->right;
        n->right = temp->left;
        temp->left = n;
        setHeight(n); //<--- set first
        setHeight(temp);
        return temp;
    }

};

我通过读取我的 main.cpp 文件来运行程序,该文件调用我的 AVLtree 的命令。我知道它有很多代码,但我很紧张,因为我找不到它可能发生的地方。谢谢。

【问题讨论】:

  • 你试过通过valgrind-memcheck运行它吗?
  • 您有泄漏,因为您手动调用newdelete。不要那么做。你是一棵简单的有向树。将子Node* 替换为std::unique_ptr&lt;Node&gt;,在需要时执行move,那么我敢说你有泄漏。您可能必须编写 templare&lt;typename T, typename...Args&gt;std::unique_ptr&lt;T&gt; make_unique(Args&amp;&amp;...args) 才能从客户端代码中删除 new,但这可能有点矫枉过正:在您的情况下,您不需要处理任意 ctor。
  • 是否有特定的命令序列导致您检测到泄漏?
  • 你怎么知道有内存泄漏?你检查过你的LinkedList 实现了吗?当我使用 _CrtDumpMemoryLeaks 在 Visual Studio 中运行它(并实例化一棵树,插入单个元素)时,我没有看到任何泄漏。

标签: c++ memory-leaks avl-tree


【解决方案1】:

您如何知道存在内存泄漏?

除非您使用某些工具来查找内存泄漏,例如 @jsantander 建议的 valgrind,否则请尝试以下操作:

  1. 避免代码重复。现在的表格有太多的重复。例如clear() 可以通过调用cleartree(root) 来简化。 insert() 类似。

  2. 打印/记录每个内存分配(new)和释放(delete)的内存

  3. 不断增加计数器newCountdeleteCount。在重要方法的末尾,添加一个断言assert( newCount - deleteCount == size );。在第一次发生内存泄漏时,assert() 会爆炸。参见http://accu.org/var/uploads/journals/overload102.pdf,第 7 页,“其他体验”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 2014-01-29
    • 1970-01-01
    相关资源
    最近更新 更多