C++ 分段错误——自平衡树插入

Posted

技术标签:

【中文标题】C++ 分段错误——自平衡树插入【英文标题】:C++ Segmentation fault -- Self-balancing Tree insertion 【发布时间】:2020-10-12 04:00:01 【问题描述】:

我正在尝试解决 Hackerrank (https://www.hackerrank.com/challenges/self-balancing-tree/problem) 上的自平衡树问题,并且在最后 3 个测试用例中不断遇到分段错误。我看到以前曾发布过同样的问题,并尝试将相同的方法(检查 nullptr)应用于我的案例,但到目前为止没有成功。以下代码是用 C++ 编写的,如果你们能帮助我,我将不胜感激。谢谢!

/* Node is defined as :
typedef struct node

    int val;
    struct node* left;
    struct node* right;
    int ht;
 node; */

node * newNode(int val)

    node * newNode = new node;
    
    newNode->val = val;
    newNode->left = nullptr;
    newNode->right = nullptr;
    newNode->ht = 0;
    
    return newNode;


int getHeight(node* root)

    if(root == nullptr) 
        return -1;
     else 
        return root->ht;
    


node* rightRotate(node* root)

    node* temp = root->left;
    root->left = temp->right;
    temp->right = root;

    root->ht = 1 + max(getHeight(root->left), getHeight(root->right));
    temp->ht = 1 + max(getHeight(temp->left), getHeight(temp->right));

    return temp;


node* leftRotate(node* root)

    node* temp = root->right;
    root->right = temp->left;
    temp->left = root;

    root->ht = 1 + max(getHeight(root->left), getHeight(root->right));
    temp->ht = 1 + max(getHeight(temp->left), getHeight(temp->right));

    return temp;


node * insert(node * root,int val)

    if(root == nullptr) 
        root = newNode(val); 
        return root;
    
    if(val > root->val) 
        root->right = insert(root->right, val);
    
    else if(val < root->val) 
        root->left = insert(root->left, val);
    
    else return 0; 
    
    root->ht = 1 + max(getHeight(root->left),getHeight(root->right));
  
    int balance = getHeight(root->left) - getHeight(root->right);
    
    if(root->left != nullptr && balance > 1) //Left subtree disbalanced
        if(val < root->left->val)  
            //Left-Left case: perform a right rotation on the disb. node
            return rightRotate(root);
        
        else 
            //Left-Right case: perfom a left rotation on the disb. node left subtree
            //and a right rotation on the disb. node
            root->left = leftRotate(root->left);
            return rightRotate(root);

        
    
    if(root->right != nullptr && balance < -1) //Right subtree disbalanced
        if(val > root->right->val)  
            //Right-Right case: perform a left rotation on the disb. node
            return leftRotate(root);
        
        else 
            //Right-Left case: perfom a right rotation on the disb. node right subtree
            //and a left rotation on the disb. node
            root->right = rightRotate(root->left);
            return leftRotate(root);
        
    
    return root;

编辑:

出于调试目的,我使用了一个在线 gdb,并在上面的代码中添加了以下遍历方法和 main 函数:

void inOrder(node* root) 
    if(root == NULL) 
        return;
     else 
        inOrder(root->left);
        cout << root->val << " ";
        inOrder(root->right);
    


int main()

    node* root=NULL;

    root=insert(root,2);
    root=insert(root,4);
    root=insert(root,3);
    
    inOrder(root);
    return 0;

尝试按此顺序插入值 2、4 和 3 后,我们将得到一棵不平衡树,因为右子树的高度为 1,而左子树的高度为 -1(叶节点为nullptr) 并且平衡因子将小于 -1。进一步分析表明,我们有一个 RIGHT-LEFT 情况,因为导致不平衡的节点是不平衡节点(根 2)的右孩子的左孩子。然后我们必须对不平衡节点右子节点执行右旋转,然后对不平衡节点本身进行左旋转,树最终应该如下所示:

   3
  / \
 2   4

【问题讨论】:

插入树中已经存在的值时的预期行为是什么? 您好@1201ProgramAlarm,感谢您的回复,回答您的评论,它不能有重复的值。 我认为他们问的原因是因为如果您尝试插入重复值,您的程序将破坏树的一部分并且还会泄漏内存。现在,这可能不是您的程序崩溃的全部原因,但这也不是一种理想的行为。换句话说,他们直接试图将您的注意力吸引到某个问题上。他们不是因为好奇才问的。 嗨@paddy,感谢您的解释和回复,我想我错过了重点。我删除了可能导致您提到的问题的else return 0; ,它没有解决分段错误,但我很高兴您指出了这一点,我完全错过了。 请提供minimal reproducible example,包括输入和预期输出。您是否尝试过使用调试器查看崩溃的位置? 【参考方案1】:

感谢所有试图帮助我解决这个问题的人,事实证明我的愚蠢程度是无限的。我相信我已经弄清楚我做错了什么。 这个问题的问题在于检查右子树是否不平衡的部分,如果是,则执行必要的旋转。在下面的代码中,应该是

root->right = rightRotate(root->right);

而不是

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

【讨论】:

以上是关于C++ 分段错误——自平衡树插入的主要内容,如果未能解决你的问题,请参考以下文章

解密树的平衡:二分搜索树 → AVL自平衡树 → 左倾红黑树

解密树的平衡:二分搜索树 → AVL自平衡树 → 左倾红黑树

将节点插入到平衡二叉搜索树

解密树的平衡:二分搜索树 → AVL自平衡树 → 红黑树

哈希表 v 自平衡搜索树

数据结构14.自平衡二叉查找树_AVL树