2013-05-09 45 views
5

Gần đây tôi đã viết một đoạn mã khá đơn giản cố gắng triển khai Cây tìm kiếm nhị phân trong C với thao tác chèn, tìm kiếm, xóa và hiển thị. Thật không may, mã này dường như không hoạt động.Tìm kiếm nhị phân Cây C thực hiện

#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; 
} 

Trong thực tế, chú ý đến dòng nhận xét printf("%d", rootNode->data); ngay trước do-while khối trong main() kết thúc. Nếu tôi bỏ ghi chú dòng này, biên dịch chương trình và chạy nó, chương trình sẽ ném một lỗi phân đoạn. Bất cứ ai có thể cho tôi biết lý do tại sao lỗi này xảy ra và tại sao mã toàn bộ không chạy? Cảm ơn trước.

Trả lời

1

Ở phía trên, bạn khai báo

node *rootNode = NULL; 

Nếu bạn không chạy insertNode (thành công - Xem câu trả lời của Matt), nút vẫn sẽ được NULL khi cố gắng in nó và đó là lý do tại sao bạn đang nhận được segfault.

+0

Tại sao bạn nên downvote? Tôi nhận ra đây không phải là câu trả lời hoàn chỉnh, nhưng OP cũng đã hỏi tại sao mã của anh ấy lại bị phân đoạn khi cố gắng in. –

5

Bạn có quan niệm sai về cách C xử lý đối số. Trong C, tất cả đối số được truyền theo giá trị, bao gồm cả con trỏ. Khi bạn gán lại một con trỏ bên trong một hàm, bạn sẽ gán lại một bản sao của con trỏ đó.

Ví dụ:

void f (int *p); 

int *p; 

f(p); 

Địa chỉ (&p) của con trỏ là khác nhau trong hàm. Cả hai đều trỏ đến cùng một vị trí (có cùng giá trị), nhưng mỗi địa chỉ có một địa chỉ khác. Khi bạn gán con trỏ cho giá trị trả về là malloc, nó chỉ gán bản sao cục bộ của con trỏ đó.

Một cách để khắc phục điều này là giới thiệu một mức độ khác biệt, và chuyển địa chỉ của con trỏ: void insertNode(int i, node **n), mà bạn có thể gọi như insertNode(0, &n). Khi bạn muốn thay đổi nó thành một thứ khác, hãy cân nhắc nó một lần và rồi chỉ định: *p = malloc(sizeof(node)).

Một giải pháp khác là để hàm trả về con trỏ và gán nó trong mã gọi: return malloc(sizeof(node)). (Lưu ý: Bạn thực sự sẽ trả lại sau mã khởi tạo ... cũng không truyền giá trị trả lại là malloc trong C).

1

Lý do mã phân cách khi bạn bỏ ghi chú printf là vì rootNode là con trỏ NULL. Dereferencing con trỏ NULL này trong lời gọi hàm gây ra segfault.

Lý do rootNode là con trỏ NULL là nó không bao giờ bị thay đổi bởi mã. Gọi insertNode() kết quả trong biến cục bộ n được đặt thành giá trị được lưu trữ trong rootNode (trong trường hợp này là NULL). Các thay đổi đối với n trong chức năng insertNode() không thay đổi rootNode.

Để sửa mã, bạn có thể thay đổi các hàm insertNodedeleteNode để chấp nhận con trỏ đến con trỏ nút gốc.Ví dụ insertCode() chức năng sẽ trở thành:

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); 
     } 
    } 
} 

Bạn cũng sẽ phải thay đổi mã để gọi insertNode() với một tham chiếu đến rootNode insertNode(num, &rootNode);

Tôi cũng khuyên bạn nên kiểm tra các giá trị trở lại của các cuộc gọi scanf khác nhau . Nếu scanf("%d",x) trả về 0 thì giá trị không được chuyển đổi thành int và nội dung của x là không xác định. Lý tưởng nhất là mã sẽ xử lý trường hợp này một cách duyên dáng.

0

Tôi nghĩ rằng probblem là với chữ ký cho Chèn chức năng Hãy thử đoạn code dưới đây và Nó sẽ làm việc

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)); 
    } 

Và sử dụng Insert Function như

insertNode(num, &rootNode); 

Trước đó, những thay đổi ở lại chức năng Insert chỉ có. Sử dụng con trỏ kép bên trong.