簡體   English   中英

在c中的二叉搜索樹中刪除操作的實現

[英]Implementation of Delete operation in a Binary Search Tree in c

我已經編寫了一個程序,它將兩個文件名作為參數f1和f2,兩個文件都帶有數字。 該程序應可調用,如下所示:tree f1 f2

f1具有數百萬個唯一數字,每行一個。 每個數字都應讀取並插入到Binary Search Tree中

插入這些文件后,程序應從第二個文件中讀取數字。 對於每個數字,必須執行以下操作:

  • 在樹中搜索號碼
  • 如果存在,請詢問用戶並將其從樹中刪除

現在,我用於插入和搜索的代碼給出了正確的結果,但是在刪除部分,出現了一些錯誤。

請通過修改我的代碼來幫助我:

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

struct node {
    int info;
    struct node *left, *right;
};

struct node *insert (struct node *root, int item)
{
    struct node *temp, *temp1, *pre;

    temp = (struct node *) malloc (sizeof (struct node));
    temp->info = item;
    temp->left = temp->right = NULL;

    if (root == NULL)
        root = temp;
    else {
        temp1 = root;
        while (temp1 != NULL) {
            pre = temp1;
            if (item < temp1->info)
                temp1 = temp1->left;
            else
                temp1 = temp1->right;

        }
        if (item < pre->info)
            pre->left = temp;
        else
            pre->right = temp;
    }

    return root;
}

struct node *create (struct node *root)
{
    int num;
    root = NULL;
    FILE *fp1 = fopen ("myFile1.txt", "r");
    if (fp1 == NULL) {
        printf ("cannot open this file");
        exit (0);
    }

    while (fscanf (fp1, "%d", &num) == 1)
        root = insert (root, num);

    return root;
    fclose (fp1);   /* (note: unreachable code) */
}

struct node *min (struct node *ptr)
{
    struct node *current = ptr;

    while (current->left != NULL)
        current = current->left;

    return current;
}

struct node *delete (struct node *root, int n)
{
    if (root == NULL)
        return root;

    if (n < root->info)
        root->left = delete (root->left, n);
    else if (n > root->info)
        root->right = delete (root->right, n);
    else {
        if (root->left == NULL) {
            struct node *p;
            p = root->right;
            free (root);
            return p;
        }
        else if (root->right == NULL) {
            struct node *p;
            p = root->left;
            free (root);
            return p;
        }

        struct node *p;
        p = min (root->right);
        root->info = p->info;
        root->right = delete (root->right, p->info);
    }

    return root;
}

void search (struct node *root)
{
    int Y, X;
    struct node *t;
    t = root;
    char ch = 'n';
    FILE *fp2 = fopen ("myFile2.txt", "r");
    if (fp2 == NULL) {
        printf ("cannot open this file");
        exit (0);
    }
    X = 0;
    while (fscanf (fp2, "%d", &Y) == 1) {
        while (t != NULL && X == 0) {
            if (Y == t->info) {
                X = 1;
                break;
            } else if (Y < t->info)
                t = t->left;
            else
                t = t->right;
        }

        if (X == 1)
            printf (" %d is found %d\n", Y, X);
        printf ("if you want to delete a number ");
        scanf ("%c", &ch);
        if (ch == 'y') {
            root = delete (root, Y);
            return root;

        }
        else
            printf ("%dNot found %d\n", Y, X);

    }
    fclose (fp2);
}

void inorder (struct node *root)
{
    if (root != NULL) {
        inorder (root->left);
        printf ("%d ", root->info);
        inorder (root->right);
    }
}

void main ()
{
    struct node *root = NULL;
    struct node *ptr = NULL;
    root = create (root);
    inorder (root);
    search (root);
    inorder (root);
}

這是更正的代碼:

#include<stdio.h>
#include<stdlib.h>
struct node
{
 int info;
 struct node *left, *right;
};
struct node* insert(struct node* root, int item)
{
 struct node *temp,*temp1,*pre;
 temp =  (struct node *)malloc(sizeof(struct node));
 temp->info = item;
 temp->left = temp->right = NULL;

 if (root == NULL)
 {
    root=temp;
 }
 else
 {
   temp1=root;
   while(temp1!=NULL)
   {
           pre=temp1;
           if(item<temp1->info)
           {
               temp1=temp1->left;
           }
           else
           {
               temp1=temp1->right;
           }
   }
   if(item<pre->info)
   {
      pre->left=temp;
   }
   else
   {
      pre->right=temp;
   }
 }
 return root;
}

struct node *create(struct node *root)
{
   int num;
   root=NULL;
   FILE *fp1=fopen("myFile1.txt","r");
   if (fp1 == NULL)
   {
        printf("cannot open this file");
        exit(0);
   }
   while(fscanf(fp1,"%d",&num)==1)
       root=insert(root,num);
   fclose(fp1);
   return root;
}
struct node * min(struct node* ptr)
{
        struct node* current = ptr;
        while (current->left != NULL)
        current = current->left;

        return current;
}
struct node* delete(struct node* root,int n)
{
   if(root==NULL)
   {
       return root;
   }
   if(n<root->info)
   {
       root->left=delete(root->left,n);
   }
   else if(n>root->info)
   {
       root->right=delete(root->right,n);
   }
   else
   {
          if(root->left==NULL)
          {
               struct node *p;
               p=root->right;
               free(root);
               return p;
          }
          else
          if(root->right==NULL)
          {
                struct node *p;
                p=root->left;
                free(root);
                return p;
          }

          struct node *p;
          p=min(root->right);
          root->info=p->info;
          root->right=delete(root->right,p->info);
   }
   return root;
}

void search(struct node *root)
{
      int Y,X;
      struct node *t;
      char ch='n';
      FILE *fp2=fopen("myFile2.txt","r");
      if (fp2 == NULL)
      {
          printf("cannot open this file");
          exit(0);
      }
      while(fscanf(fp2,"%d",&Y)==1)
      {
            t = root;
            X = 0;
            while(t!=NULL && X==0)
            {
               if(Y==t->info)
               {
                     X=1;
                     break;
               }
               else
               {
                 if(Y<t->info)
                 {
                     t=t->left;
                 }
                 else
                 {
                     t=t->right;
                 }
               }
            }

            if(X==1)
            {
              printf("\n%d is found\n",Y);
              printf("\nDo you want to delete %d (y/n): ",Y);
              scanf(" %c",&ch);
              if(ch=='y')
              {
                 root=delete(root,Y);
              }
            }
            else
            {
                printf("\n%d Not found %d\n",Y,X);
            }
      }
      fclose(fp2);
 }

 void inorder(struct node *root)
 {
          if (root != NULL)
          {
               inorder(root->left);
               printf("%d ", root->info);
               inorder(root->right);
          }
 }

 void main()
 {
       struct node *root = NULL;
       struct node *ptr = NULL;
       root=create(root);
       inorder(root);
       printf("\n");
       search(root);
       printf("\n");
       inorder(root);
       printf("\n");
 }

除了格式的細微變化外,主要變化如下:

  • 始終記住,即使每個控制語句有一個操作,也要在每個控制語句 (如果、、、、、等等)上放置{}大括號,因為稍后,可能會將代碼添加到同一控制語句中,而忘記大括號將意味着該控制語句不會應用於該代碼。 例如,您忘記了大括號:

     if(X==1) printf(" %d is found %d\\n",Y,X); printf("if you want to delete a number "); scanf("%c",&ch); if(ch=='y') { root=delete(root,Y); return root; } else printf("%dNot found %d\\n",Y,X); 

    現在由於缺少括號,將else應用於if(ch=='y')而不是if(X==1)

  • 其次,每當將條件變量初始化為一個值並對其進行檢查時,它都位於嵌套循環內,並且要針對多個輸入或情況重復進行該操作,則初始化也需要在循環內完成。 t = root;時也是如此t = root; X = 0; search功能中,它們僅被設置一次,並且當從文件中讀取下一個數字時,它們不會再次初始化。

  • 您稱return root; ,在void search(struct node *root)函數中,該函數的返回類型為void ,表示不返回任何內容

     if(ch=='y') { root=delete(root,Y); return root; } 

    並且, return調用意味着該函數將停止進一步的執行,然后,在那里,將不執行return調用下方的其余代碼,這不是您想要的,就像在下面這樣:

     struct node *create(struct node *root) { int num; ... while(fscanf(fp1,"%d",&num)==1) root=insert(root,num); return root; fclose(fp1); } 

    在這里, fclose(fp1); 永遠不會被打電話。

  • 最后但並非最不重要的一點是,更好的代碼縮進可以幫助理解每個控制語句的作用范圍,而不必跟蹤每個左括號{到其右括號}

從長遠來看,您還希望在其他幾個方面避免給自己造成問題。 您要避免在代碼主體中對文件名進行硬編碼 ,而要避免在函數中隱藏硬編碼的文件名。 如果您需要對文件進行操作(例如createsearch文件),請將FILE*參數(或文件名)傳遞給函數。 這將使您的代碼更具可維護性和可重用性。 對於create您將執行以下操作:

struct node *create (struct node *root, FILE *fp)
{
    int num;
    root = NULL;

    while (fscanf (fp, "%d", &num) == 1)
        root = insert (root, num);

    return root;
}

對於當前search您可以執行以下操作:

void search (struct node *root, FILE *fp)
{
    int v;

    while (fscanf (fp, "%d", &v) == 1) {

        struct node *t = root;
        char ch = 'n';

        while (t != NULL) {
            if (t->info == v) {
                printf ("\n%d is found\n", v);
                printf ("\nDo you want to delete %d (y/n): ", v);
                scanf (" %c", &ch);
                if (ch == 'y') {
                    root = delete (root, v);
                }
                break;
            } 
            else {
                if (v < t->info)
                    t = t->left;
                else
                    t = t->right;
            }
        }
        if (!t)
            printf ("\n%d Not found\n", v);
    }
}

但是,為什么要傳遞FILE *指針開始search呢? 不應search通過您的樹只是搜索和返回一個指向包含匹配值(如果存在)或節點NULL ,否則? 毫無疑問,這將使search成為您的樹在許多不同情況下使用的通用功能,而不是一次性檢查第二個文件中的匹配值。

然后如何處理獲取代碼所需的文件名信息? 正如將必需的參數傳遞給在代碼中調用的每個函數一樣,您可以以相同的方式將必需的信息傳遞給main main接受命令行中給出的參數,並將其傳遞給程序。 main的一般形式是:

int main (int argc, char **argv)

(您還將看到等效的形式int main (int argc, char *argv[]) ,該形式僅反映argv的替代形式,而不顯示將數組作為函數傳遞給指針時自動發生的數組轉換結果論點)

使用參數將信息獲取到main而不是硬編碼。 這並不意味着您無法在代碼中提供默認文件名,如果沒有提供參數,則將使用默認文件名。 您可以使用三元運算符,該運算符基本上是形式(condition) ? true_value : false_value if-else簡寫形式(condition) ? true_value : false_value (condition) ? true_value : false_value 有了它,您可以從命令行獲取文件名,同時仍然為沒有提供參數的情況下要使用的文件名提供默認值(注意:第一個參數將始終用作fp1 )。 例如:

int main (int argc, char **argv)
{
    FILE *fp1 = fopen (argc > 1 ? argv[1] : "myfile1.txt", "r");
    FILE *fp2 = fopen (argc > 2 ? argv[2] : "myfile2.txt", "r");
    if (fp1 == NULL) {
        fprintf (stderr, "cannot open fp1\n");
        return 1;
    }
    if (fp2 == NULL) {
        fprintf (stderr, "cannot open fp2\n");
        return 1;
    }

然后,您可以將FILE*指針( fp1fp2 )傳遞給需要它們的任何函數,例如:

root = create (root, fp1);

createsearch刪除了硬編碼的文件名后,您可以將注意力轉移到創建search ,而不僅僅是從第二個文件中檢查匹配值。 重寫search ,它只需要指向root和要搜索的值的指針,然后可以返回指示是否在樹中找到該值的指示(通常是指向包含該值的節點的指針),並返回NULL指針。 例如:

struct node *search (struct node *root, int v)
{
    struct node *t = root;

    while (t != NULL) {
        if (t->info == v)
            return t;
        else {
            if (v < t->info)
                t = t->left;
            else
                t = t->right;
        }
    }
    return t;
}

為了以可維護的方式完成代碼,您只需要編寫一個函數即可從第二個文件中讀取值, search樹,然后在發現值時提示允許刪除。 同樣,它僅需要指向root的指針和用於讀取值的FILE*指針作為參數。 然后,它可以處理呼叫search並從那里delete (注意:可以將delete重寫為直接對search返回的指針進行操作,以避免再次遍歷,但這是另一天)。 例如,您的檢查和提示刪除功能可能是:

void check_delete (struct node *root, FILE *fp)
{
    int v;

    while (fscanf (fp, "%d", &v) == 1) {

        char ch = 'n';

        if (search (root, v)) {

            printf ("\n%d is found\n", v);
            printf ("\nDo you want to delete %d (y/n): ", v);
            scanf (" %c", &ch);

            if (ch == 'y')
                root = delete (root, v);
        }
        else
            printf ("\n%d Not found\n", v);
    }
}

將難題的所有部分放在一起,並在main上方提供函數原型 (該結構最終將與struct一起移至適當的頭文件),並在下面提供函數定義 (最終將其移至單獨的源文件中),將以類似於以下代碼的結尾。 注意,這並不是要包含所有建議的更改或改進的詳盡重寫,但是重要的是要開始以正確的方式處理代碼所需的信息,並避免過早地養成不良習慣。 如果您還有其他問題,請告訴我:

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

struct node {
    int info;
    struct node *left, *right;
};

/* function prototypes */
struct node *insert (struct node *root, int item);
struct node *create (struct node *root, FILE *fp);
struct node *min (struct node *ptr);
struct node *delete (struct node *root, int n);
struct node *search (struct node *root, int v);
void check_delete (struct node *root, FILE *fp);
void inorder (struct node *root);

int main (int argc, char **argv)
{
    FILE *fp1 = fopen (argc > 1 ? argv[1] : "myfile1.txt", "r");
    FILE *fp2 = fopen (argc > 2 ? argv[2] : "myfile2.txt", "r");
    if (fp1 == NULL) {
        fprintf (stderr, "cannot open fp1\n");
        return 1;
    }
    if (fp2 == NULL) {
        fprintf (stderr, "cannot open fp2\n");
        return 1;
    }
    struct node *root = NULL;

    root = create (root, fp1);
    fclose (fp1);

    inorder (root);
    putchar ('\n');

    check_delete (root, fp2);
    fclose (fp2);
    putchar ('\n');

    inorder (root);
    putchar ('\n');

    return 0;
}

struct node *insert (struct node *root, int item)
{
    struct node *temp, *temp1, *pre;

    temp = malloc (sizeof *temp);
    temp->info = item;
    temp->left = temp->right = NULL;

    if (root == NULL) {
        root = temp;
    } 
    else {
        temp1 = root;

        while (temp1 != NULL) {
            pre = temp1;
            if (item < temp1->info)
                temp1 = temp1->left;
            else
                temp1 = temp1->right;
        }

        if (item < pre->info)
            pre->left = temp;
        else
            pre->right = temp;
    }

    return root;
}

struct node *create (struct node *root, FILE *fp)
{
    int num;
    root = NULL;

    while (fscanf (fp, "%d", &num) == 1)
        root = insert (root, num);

    return root;
}

struct node *min (struct node *ptr)
{
    struct node *current = ptr;
    while (current->left != NULL)
        current = current->left;

    return current;
}

struct node *delete (struct node *root, int n)
{
    if (root == NULL) {
        return root;
    }
    if (n < root->info) {
        root->left = delete (root->left, n);
    } else if (n > root->info) {
        root->right = delete (root->right, n);
    } else {
        if (root->left == NULL) {
            struct node *p;
            p = root->right;
            free (root);
            return p;
        } else if (root->right == NULL) {
            struct node *p;
            p = root->left;
            free (root);
            return p;
        }

        struct node *p;
        p = min (root->right);
        root->info = p->info;
        root->right = delete (root->right, p->info);
    }
    return root;
}

struct node *search (struct node *root, int v)
{
    struct node *t = root;

    while (t != NULL) {
        if (t->info == v)
            return t;
        else {
            if (v < t->info)
                t = t->left;
            else
                t = t->right;
        }
    }
    return (t);
}

void check_delete (struct node *root, FILE *fp)
{
    int v;

    while (fscanf (fp, "%d", &v) == 1) {

        // struct node *t = root;
        char ch = 'n';

        if (search (root, v)) {

            printf ("\n%d is found\n", v);
            printf ("\nDo you want to delete %d (y/n): ", v);
            scanf (" %c", &ch);

            if (ch == 'y')
                root = delete (root, v);
        }
        else
            printf ("\n%d Not found\n", v);
    }
}

void inorder (struct node *root)
{
    if (root != NULL) {
        inorder (root->left);
        printf ("%d ", root->info);
        inorder (root->right);
    }
}

暫無
暫無

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

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