簡體   English   中英

BST C++ 段錯誤的實現

[英]Implementation of BST C++ Segmentation Fault

我在 C++ 中實現了二叉搜索樹,但出於某種原因,我沒有看到分段錯誤發生的位置。 但我確實注意到,當我在 addNode 的第一個條件語句中注釋掉 root = node 時,錯誤消失了。 什么是分段錯誤,它與指針有什么關系?

#include <iostream>
#include <iomanip>
using namespace std;

class bstNode
{
public:
    int value;
    bstNode *left;
    bstNode *right;

    bstNode(){};
    ~bstNode(){};

    bstNode(int value)
    {
        this->value = value;
        this->left = NULL;
        this->right = NULL;
    }

    bstNode(int value, bstNode *left, bstNode *right)
    {
        this->value = value;
        this->left = left;
        this->right = right;
    }

    bstNode *root;

    void addNode(int value)
    {
        if (root == NULL)
        {
            bstNode *node = new bstNode(value);
            root = node;
        }
        else
        {
            bstNode *focusNode = root;
            bstNode *parent;

            while (focusNode != NULL)
            {
                if (value > focusNode->value)
                {
                    focusNode = focusNode->right;
                    if (focusNode == NULL)
                    {
                        focusNode->right = new bstNode(value);
                    }
                }
                else
                {
                    focusNode = focusNode->left;
                    if (focusNode == NULL)
                    {
                        focusNode->left = new bstNode(value);
                    }
                }
            }
        }
    }

    static void printBST(bstNode *node)
    {
        while (node != NULL)
        {
            printBST(node->left);
            cout << node->value;
            printBST(node->right);
        }
    }
};

int main()
{
    bstNode *node = new bstNode();
    node->addNode(7);
    node->addNode(2);
    node->addNode(18);
    node->addNode(6);
    node->addNode(4);
    node->addNode(23);

    bstNode::printBST(node->root);

    return 0;
}

直接錯誤是這個

                if (focusNode == NULL) {

                    focusNode->left = new bstNode(value);
                }

這顯然是錯誤的,如果指針是 null 你就不能使用它。 你在多個地方都有這個。 修復該問題,然后在您通過該問題后更新問題。 我怎么知道的? 我在我的調試器下運行了你的代碼,它立即告訴我,你應該學習如何充分利用你的調試器。

下一個

void addNode(int value)

作為定義為 class 的方法

class bstNode {

public:
    int value;

是非常糟糕的做法。 在那種方法中, value指的是什么? 參數或成員變量。 養成像這樣給成員變量指定名稱的習慣

class bstNode {

public:
    int value_;

還有輕微的虱子。 命名類的公認風格是像這樣使用前導大寫字母

class BstNode {

public:
    int value_;

甚至

class BSTNode

class bstNode {

public:
    int value_;

在下面的代碼中...

while(focusNode != NULL){

    if(value > focusNode->value){

        focusNode = focusNode->right;
        if(focusNode == NULL){
            
            focusNode->right = new bstNode(value);
        }
    }
    else{

        focusNode = focusNode->left;
        if(focusNode == NULL){

            focusNode->left = new bstNode(value);
        }
    }

}

...您正在引用保證為 NULL 的節點的子節點,因為您使用條件語句驗證了這一點。 由於節點本身不存在,因此它沒有子節點之類的屬性。 想象一下,您正試圖與一個從未存在過的人的孩子交流。

變量focusNode存儲節點的地址。 focusNode->value所做的是它轉到其地址focusNode存儲並從那里檢索 value 屬性的節點。

focusNodeNULL時,它不指向任何節點,因此您不能在那里 go 並檢索它的 value 屬性。

我編寫了您可以用 while 循環替換的代碼。 我已經測試過它並且有效:

while(true){
    if(value > focusNode->value){

        if(focusNode->right == NULL){
            focusNode->right = new bstNode(value);
            return;
        } else focusNode = focusNode->right;
    }
    else{

        if(focusNode->left == NULL){
            focusNode->left = new bstNode(value);
            return;
        } else focusNode = focusNode->left;
    }

}

我還修復了您的printBST function。在printBST function 中使用if而不是while ,因為 while 循環內的代碼將被執行無限次而不是一次打印 BST。

static void printBST(bstNode* node){

    if(node != NULL){
    
        printBST(node->left);
        cout << node->value <<" ";
        printBST(node->right);
    }
}
using namespace std;

我一般建議不要這樣做。 很難確定命名空間std中有什么,但簡短的總結是“很多,而且一直都在增加”,因此讓所有這些直接可見可能會導致問題。

bstNode(){};
~bstNode(){};

這些並沒有真正完成任何有用的事情。 構造函數的目的是初始化 object,但這些只會讓 object 未初始化,這可能會導致問題——尤其是當/如果您嘗試取消引用未初始化的指針時出現分段錯誤。

bstNode(int value){

    this->value = value;
    this->left = NULL;
    this->right = NULL;
}

這樣更好,但我更喜歡使用成員初始化列表而不是 ctor 體內的賦值,而且我更喜歡nullptr而不是NULL

bstNode(int value) 
    : value(value)
    , left(nullptr)
    , right(nullptr) {}

下一個:

bstNode(int value, bstNode* left, bstNode* right){

    this->value = value;
    this->left = left;
    this->right = right;
}

...寫得很好(盡管它也可以使用成員初始化列表,這通常更可取),但在構建二叉搜索樹時很少有用,因為在正常使用中你只會插入新的葉節點,而不是新的內部節點節點。

void addNode(int value){

    if (root == NULL){

        bstNode* node = new bstNode(value);
        root = node;
    }
    else{

        bstNode* focusNode = root;
        bstNode* parent;

        while(focusNode != NULL){

            if(value > focusNode->value){

                focusNode = focusNode->right;
                if(focusNode == NULL){
                    
                    focusNode->right = new bstNode(value);
                }
            }
            else{

                focusNode = focusNode->left;
                if(focusNode == NULL){

                    focusNode->left = new bstNode(value);
                }
            }
        }    
    }
}

這至少是分段錯誤的一個明顯來源——您在驗證指針是 null 后立即取消引用它。

至少對於第一次嘗試,我想我會使用遞歸實現,它往往更簡單:

void addNode(int value, bstNode *&node = root) { 
    if (node == nullptr) {
        node = new node(value);
    } else if (value < node->value) {
        addNode(value, node->left);
    } else if (value > node->value) {
        addNode(value, node->right);
    } else {
        // attempt at inserting duplicate value
    }
}

請注意,這傳遞了對指針的引用,因此我們可以修改“當前”指針,而不必在遍歷樹時跟蹤父指針。

static void printBST(bstNode* node){

    while(node != NULL){
        printBST(node->left);
        cout << node->value;
        printBST(node->right);
    }    
}

由於我們遞歸地執行此操作,因此我們不需要(甚至不需要)循環。 遍歷左子樹,當前節點,右子樹遍歷整棵樹,不需要迭代。

另請注意,這不會在節點中的數字之間打印任何分隔符,因此包含12, 34的樹和包含1, 2, 3, 4的樹都將打印為1234 ,這可能不是很有用. 幸運的是,添加分隔符非常容易。

static void printBST(bstNode* node){

    if (node != nullptr){
        printBST(node->left);
        cout << node->value << ' ';
        printBST(node->right);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM