【问题标题】:Binary Search Tree C implementation二叉搜索树 C 实现
【发布时间】:2013-05-03 09:39:23
【问题描述】:

我最近编写了一段相当简单的代码,试图用 C 语言实现一个具有插入、搜索、删除和显示操作的二叉搜索树。不幸的是,代码似乎不起作用。

#include <stdio.h>
#include <stdlib.h>

struct TreeNode {
    int data;
    struct TreeNode *leftChildNode;
    struct TreeNode *rightChildNode;
};

typedef struct TreeNode node;
node *rootNode = NULL;

void insertNode(int i, node *n) {
    if(n == NULL) {
        n = (node*)malloc(sizeof(node));
        n->leftChildNode = NULL;
        n->rightChildNode = NULL;
        n->data = i;
    }
    else 
    if(n->data == i)
        printf("\nThis value already exists in the tree!");
    else
    if(i > n->data)
        insertNode(i, n->rightChildNode);
    else
        insertNode(i, n->leftChildNode);
    }

void searchNode(int i, node *n) {
    if(n == NULL)
        printf("\nValue does not exist in tree!");
    else
    if(n->data == i)
        printf("\nValue found!");
    else
    if(i > n->data)
        searchNode(i, n->rightChildNode);
    else
        searchNode(i, n->leftChildNode);
    }

void deleteNode(int i, node *n) {
    if(n == NULL)
        printf("\nValue does not exist in tree!");
    else
    if(n->data == i) {
        if(n->leftChildNode == NULL)
            n = n->rightChildNode;
        else
        if(n->rightChildNode == NULL)
            n = n->leftChildNode;
        else {
            node *temp = n->rightChildNode;
            while(temp->leftChildNode != NULL)
                temp = temp->leftChildNode;
            n = temp;
        }
    }
    else
    if(i > n->data)
        deleteNode(i, n->rightChildNode);
    else
        deleteNode(i, n->leftChildNode);
    }

void displayPreOrder(node *n) {
    if(n != NULL) {
        printf("%d ", n->data);
        displayPreOrder(n->leftChildNode);
        displayPreOrder(n->rightChildNode);
    }
}

void displayPostOrder(node *n) {
    if(n != NULL) {
        displayPostOrder(n->leftChildNode);
        displayPostOrder(n->rightChildNode);
        printf("%d ", n->data);
    }
}

void displayInOrder(node *n) {
    if(n != NULL) {
        displayInOrder(n->leftChildNode);
        printf("%d ", n->data);
        displayInOrder(n->rightChildNode);
    }
}

int main(void) {
    int ch, num, num1;
    do {
        printf("\nSelect a choice from the menu below.");
        printf("\n1. Insert a node.");
        printf("\n2. Search for a node.");
        printf("\n3. Delete a node.");
        printf("\n4. Display the Binary Search Tree.");
        printf("\nChoice: ");
        scanf("%d", &ch);
        switch(ch) {
            case 1: printf("\nEnter an element: ");
                    scanf("%d", &num);
                    //printf("YESYES");
                    insertNode(num, rootNode);
                    break;

            case 2: printf("\nEnter the element to be searched for: ");
                    scanf("%d", &num);
                    searchNode(num, rootNode);
                    break;

            case 3: printf("\nEnter the element to be deleted: ");
                    scanf("%d", &num);
                    deleteNode(num, rootNode);
                    break;

            case 4: printf("\nSelect an order for the elements to be display in.");
                    printf("\n1. Pre-order.");
                    printf("\n2. Post-order.");
                    printf("\n3. In-order.");
                    printf("\nChoice: ");
                    scanf("%d", &num1);
                    switch(num1) {
                        case 1: printf("\nPre-order Display: ");
                                displayPreOrder(rootNode);
                                break;

                        case 2: printf("\nPost-order Display: ");
                                displayPostOrder(rootNode);
                                break;

                        case 3: printf("\nIn-order Display: ");
                                displayInOrder(rootNode);
                                break;

                        default: exit(0);
                    }
                    break;

            default: exit(0);
            }
        //printf("%d", rootNode->data);
        printf("\nIf you want to return to the menu, press 1.");
        printf("\nChoice: ");
        scanf("%d", &num);
    } while(num == 1);

    return 0;
}

事实上,请注意main() 中的do-while 块结束之前的注释行printf("%d", rootNode-&gt;data);。如果我取消注释这一行,编译程序并运行它,程序会引发分段错误。谁能告诉我为什么会发生这个错误以及为什么整个代码没有运行?提前致谢。

【问题讨论】:

    标签: c binary-search-tree


    【解决方案1】:

    在顶部,你声明

    node *rootNode = NULL; 
    

    如果您不运行 insertNode(成功 - 请参阅 Matt 的回答),则尝试打印时节点仍将为 NULL,这就是您遇到段错误的原因。

    【讨论】:

    • 为什么投反对票?我意识到这不是完整的答案,但 OP 也询问了为什么他的代码在尝试打印时会出现段错误。
    【解决方案2】:

    您对 C 处理参数的方式有误解。在 C 中,所有参数都按值传递,包括指针。当您在函数内部重新分配指针时,您正在重新分配该指针的副本。

    例如:

    void f ( int *p );
    
    int *p;
    
    f(p);
    

    函数中指针的地址(&amp;p)不同。它们都指向同一个位置(具有相同的值),但每个都有不同的地址。当您将指针分配给malloc 的返回值时,它只是分配该指针的函数本地副本。

    解决此问题的一种方法是引入另一个间接级别,并传递指针的地址:void insertNode(int i, node **n),您可以像 insertNode(0, &amp;n) 一样调用它。当您想将其更改为其他内容时,将其取消引用一次并然后分配:*p = malloc(sizeof(node))

    另一个解决方案是让函数返回指针并在调用代码中分配它:return malloc(sizeof(node))。 (注意:你实际上会在初始化代码之后返回它......也不要在C中转换malloc的返回值)。

    【讨论】:

      【解决方案3】:

      取消注释 printf 语句时代码段错误的原因是因为 rootNode 是一个 NULL 指针。在函数调用中取消引用这个 NULL 指针会导致段错误。

      rootNode 是 NULL 指针的原因是它永远不会被代码更改。调用insertNode() 会导致局部变量n 被设置为存储在rootNode 中的值(在本例中为NULL)。 insertNode() 函数中对n 的更改不会更改rootNode

      要修复代码,您可以更改 insertNodedeleteNode 函数以接受指向根节点指针的指针。例如insertCode() 函数将变为:

      void insertNode(int i, node **n) {
          if(*n == NULL) {
              (*n) = (node*)malloc(sizeof(node));
              (*n)->leftChildNode = NULL;
              (*n)->rightChildNode = NULL;
              (*n)->data = i;
          }
          else
          {
              if((*n)->data == i)
              {
                  printf("\nThis value already exists in the tree!");
              }
              else
              {
                  if(i > (*n)->data)
                      insertNode(i, &(*n)->rightChildNode);
                  else
                      insertNode(i, &(*n)->leftChildNode);
              }
          }
      }
      

      您还必须更改代码以调用 insertNode() 并引用 rootNode insertNode(num, &amp;rootNode);

      我还建议您检查各种 scanf 调用的返回值。如果scanf("%d",x) 返回 0,则该值不会转换为 int,并且 x 的内容未定义。理想情况下,代码会优雅地处理这种情况。

      【讨论】:

        【解决方案4】:

        我认为问题在于插入函数的签名尝试下面的代码,它会工作

        void insertNode(int i, node **n) {
            if(*n == NULL) {
                *n = (node*)malloc(sizeof(node));
                (*n)->leftChildNode = NULL;
                (*n)->rightChildNode = NULL;
                (*n)->data = i;
            }
            else 
            if((*n)->data == i)
                printf("\nThis value already exists in the tree!");
            else
            if(i > (*n)->data)
                insertNode(i, &((*n)->rightChildNode));
            else
                insertNode(i, &((*n)->leftChildNode));
            }
        

        并使用插入函数作为

        insertNode(num, &rootNode);
        

        之前的更改仅保留在插入功能中。在里面使用双指针。

        【讨论】:

          猜你喜欢
          • 2015-07-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-24
          相关资源
          最近更新 更多