鱼C论坛

 找回密码
 立即注册
查看: 2913|回复: 1

数据结构—二叉查找树相关

[复制链接]
发表于 2020-11-7 19:44:28 | 显示全部楼层 |阅读模式
30鱼币
下面代码中有两个删除二叉查找树结点的函数,一个是用递归来找目标节点,一个是循环来找目标节点。本意都是找目标节点,但是当我使用循环删除结点时时,后面的中序(或换成前序遍历)就会显示溢出。劳烦各位鱼油帮我看看啦~~

  1. /*
  2. 二叉查找树 BST

  3. 1.二叉查找树的结构体
  4. 2.插入
  5. 3.删除
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>

  9. typedef int Elemtype;
  10. typedef struct TNode{
  11.         Elemtype data;
  12.         struct TNode *lchild, *rchild;
  13. }TNode, *Tree;

  14. Tree SearchBST (Tree T, Elemtype K);
  15. void Delete (Tree *T);
  16. int DeleteBST (Tree *T, Elemtype key);
  17. int In_orderTraversal(Tree T);

  18. //(递归)数据的查找,返回目标结点或NULL
  19. Tree SearchBST (Tree T, Elemtype K)
  20. {
  21.         if (T == NULL || T->data == K)
  22.                 return T;
  23.         else if (K > T->data)
  24.                 return SearchBST (T->rchild, K);
  25.         else
  26.                 return SearchBST (T->lchild, K);
  27. }

  28. //标准数据的插入
  29. void InsertBST (Tree *T, Elemtype K)
  30. {
  31.         if (*T == NULL)
  32.         {
  33.                 *T = (Tree)malloc(sizeof(TNode));
  34.                 (*T)->data = K;
  35.                 (*T)->lchild = NULL;
  36.                 (*T)->rchild = NULL;
  37.         }
  38.         else if (K > (*T)->data)
  39.                 InsertBST (&((*T)->rchild), K);
  40.         else if (K < (*T)->data) //这步也重要,因为要过滤掉相等的元素
  41.                 InsertBST (&((*T)->lchild), K);
  42. }

  43. ////标准数据的删除
  44. //int DeleteBST (Tree *T, Elemtype key)
  45. //{
  46. //        if (*T == NULL)
  47. //                return 0;
  48. //       
  49. //        //查找合适的结点
  50. //        if (key > (*T)->data)
  51. //                return DeleteBST (&(*T)->rchild, key);
  52. //        else if (key < (*T)->data)
  53. //                return DeleteBST (&(*T)->lchild, key);
  54. //        else
  55. //        {
  56. //                printf ("(删除%d)", (*T)->data);
  57. //                Delete (T);
  58. //                return 1;
  59. //        }
  60. //}

  61. ////标准数据的删除
  62. //int DeleteBST (Tree *T, Elemtype key)
  63. //{
  64. //        Tree current;
  65. //       
  66. //        current = *T;
  67. //        //查找合适的结点
  68. //        while (current != NULL)
  69. //        {
  70. //                if (key > current->data)
  71. //                        current = current->rchild;
  72. //                else if (key < current->data)
  73. //                        current = current->lchild;
  74. //                else
  75. //                {
  76. //                        printf ("(删除%d)", current->data);
  77. //                        Delete (&current);
  78. //                        return 1;
  79. //                }
  80. //        }
  81. //        return 0;
  82. //}

  83. void Delete (Tree *T)
  84. {
  85.         Tree temp;
  86.         Tree cur; //当前的结点
  87.        
  88.         //ps:不需要特意去判断是否没有两个孩子
  89.         if ((*T)->lchild == NULL) //结点没左孩子
  90.         {
  91.                 temp = *T;
  92.                 *T = (*T)->rchild; //接上右孩子
  93.                 free (temp);
  94.         }
  95.         else if ((*T)->rchild == NULL)//结点没右孩子
  96.         {
  97.                 temp = *T;
  98.                 *T = (*T)->lchild; //接上左孩子
  99.                 free (temp);
  100.         }
  101.         else //两个孩子都有
  102.         {
  103.                 cur = (*T)->lchild;
  104.                 while (cur->rchild != NULL) //找左子树中最大的结点(左子树中最右边)
  105.                         cur = cur->rchild;
  106.                
  107.                 (*T)->data = cur->data; //移动位置 (数据)
  108.                 Delete (&cur); //删除左子树的最大结点(缓存)
  109.         }
  110. }

  111. int In_orderTraversal(Tree T)
  112. {
  113.         if (T == NULL)
  114.                 return 0;
  115.        
  116.         printf ("-%d-", T->data); //输出数据
  117.         In_orderTraversal(T->lchild); //不断查找左子树
  118.         In_orderTraversal(T->rchild); //如果存在右子树的话,就查右子树有无左子树
  119. }

  120. int main (void)
  121. {
  122.         Tree T = NULL;
  123.         int num;
  124.        
  125.         scanf ("%d", &num);
  126.         while (num != 0)
  127.         {
  128.                 InsertBST (&T, num);
  129.                 scanf ("%d", &num);
  130.         }
  131.        
  132.         In_orderTraversal (T); //中序遍历
  133.        
  134.         scanf ("%d", &num);
  135.         while (num != 0)
  136.         {
  137.                 DeleteBST (&T, num);
  138.                 In_orderTraversal (T); //中序遍历
  139.                 scanf ("%d", &num);
  140.         }
  141.        
  142.         return 0;
  143. }
复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-11-10 11:14:42 | 显示全部楼层
本帖最后由 xieglt 于 2020-11-10 11:21 编辑

该了两个函数

  1. int DeleteBST (Tree *T, Elemtype key)
  2. {
  3.         Tree current = *T;
  4.         Tree father = *T;
  5.         int flag = 0;
  6.        
  7.         //问题出在删除当点节点后,当前节点在其父节点中的链接并没有被改变。
  8.         //因此,需要设置一个当前节点的父节点指针,删除当前节点后,重新设置
  9.         //在父节点中的链接
  10.         while(current != NULL)
  11.         {
  12.                 if(key > current->data)
  13.                 {
  14.                         father = current;
  15.                         current = current->rchild;
  16.                         flag = -1;
  17.                 }
  18.                 else if(key < current->data)
  19.                 {
  20.                         father = current;
  21.                         current = current->lchild;
  22.                         flag = 1;
  23.                 }
  24.                 else
  25.                 {
  26.                         printf("删除(%d)",key);
  27.                         Delete(&current);
  28.                         //根据 flag 重新链接树
  29.                         //flag = 0 ,则删除的是根节点
  30.                         if(flag == 0)
  31.                         {
  32.                                 *T = current;
  33.                         }
  34.                         //=-1 删除的是父节点的右节点
  35.                         else if(flag == -1)
  36.                         {
  37.                                 father->rchild = current;
  38.                         }
  39.                         //=1 删除的是父节点的左节点
  40.                         else
  41.                         {
  42.                                 father->lchild = current;
  43.                         }
  44.                         break;
  45.                 }
  46.         }
  47.         return 0;
  48. }

  49. void Delete (Tree *T)
  50. {
  51.         Tree temp;
  52.         Tree cur; //当前的结点
  53.         
  54.         //ps:不需要特意去判断是否没有两个孩子
  55.         if ((*T)->lchild == NULL) //结点没左孩子
  56.         {
  57.                 temp = *T;
  58.                 *T = (*T)->rchild; //接上右孩子
  59.                 free (temp);
  60.         }
  61.         else if ((*T)->rchild == NULL)//结点没右孩子
  62.         {
  63.                 temp = *T;
  64.                 *T = (*T)->lchild; //接上左孩子
  65.                 free (temp);
  66.         }
  67.         else //两个孩子都有
  68.         {
  69.                         /*
  70.                 cur = (*T)->lchild;
  71.                 while (cur->rchild != NULL) //找左子树中最大的结点(左子树中最右边)
  72.                         cur = cur->rchild;
  73.                 (*T)->data = cur->data; //移动位置 (数据)
  74.                 Delete (&cur); //删除左子树的最大结点(缓存)
  75.                         */
  76.                         /*
  77.                         按照规则,左子节点小于父节点,右子节点大于父亲节点,比如
  78.                                          10
  79.                                          |
  80.                                         / \
  81.                                       5  20(删除20)
  82.                                          /   \
  83.                                         16    25
  84.                                        /  \    / \
  85.                                       15  18   24 26
  86.                                           / \
  87.                                        17  19
  88.                         按规则删除20后,将该节点替换其子节点16,其右节点25应该作为19的右子节点
  89.                         代码实现如下:
  90.                         */
  91.                         //取得当前节点
  92.                         temp = * T;
  93.                         //保存当前节点的右子节点
  94.                         cur = (*T)->rchild;
  95.                         //将当前节点替换为其左子节点
  96.                         *T = (*T)->lchild;
  97.                         //释放内存
  98.                         free(temp);
  99.                         //找左子节点中的最右子节点。
  100.                         temp = *T;
  101.                         while(temp->rchild != NULL)
  102.                         {
  103.                                 temp = temp->rchild;
  104.                         }
  105.                         //连接右子节点
  106.                         temp->rchild = cur;
  107.         }
  108. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 22:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表