• 数据结构-二叉排序树(建立、查找、修改)


    二叉排序树概念

    二叉排序树是动态查找表的一种,也是常用的表示方法。

    其中,它具有如下性质:

    1.若它的左子树非空,则其左子树的所有节点的关键值都小于根节点的关键值。

    2.若它的右子树非空,则其右子树的所有节点的关键值都大于根结点的关键值。

    3.它的左右子树也分别都是二叉排序树。

    PS:对二叉排序树进行中序遍历,得到的序列,总会是一个升序的数列。

    二叉排序树的建立

    我们使用C语言来建立。

    其中我们对二叉排序树的结构体定义如下:

    1. typedef int ElemType;
    2. typedef struct BTNode{
    3. ElemType key;
    4. struct BTNode *lchild,*rchild;
    5. }BTNode,*BSTree;

    建立二叉排序树的代码如下:

    1. BSTree InsertBST(BSTree bst,BSTree s) //遍历二叉排序树,找到合适的位置
    2. {
    3. if(bst==NULL)
    4. bst = s;
    5. else{
    6. if(s->key < bst->key)
    7. bst->lchild = InsertBST(bst->lchild,s);
    8. if(s->key > bst->key){
    9. bst->rchild = InsertBST(bst->rchild,s);
    10. }
    11. }
    12. return bst;
    13. }
    14. BSTree CreateBST() //建立二叉排序树
    15. {
    16. BSTree bst,s;
    17. int key;
    18. bst = NULL;
    19. printf("请输入关键字值,输入-1结束.\n");
    20. while(1){
    21. scanf("%d",&key);
    22. if(key!=-1){
    23. s = (BSTree)malloc(sizeof(BTNode));
    24. s->key = key;
    25. s->lchild = NULL;
    26. s->rchild = NULL;
    27. bst = InsertBST(bst,s);
    28. printf("成功.\n");
    29. }
    30. else
    31. break;
    32. }
    33. return bst;
    34. }

    二叉排序树的插入

    1. BSTree InsertBST(BSTree bst,BSTree s) //遍历二叉排序树,找到合适的位置
    2. {
    3. if(bst==NULL)
    4. bst = s;
    5. else{
    6. if(s->key < bst->key)
    7. bst->lchild = InsertBST(bst->lchild,s);
    8. if(s->key > bst->key){
    9. bst->rchild = InsertBST(bst->rchild,s);
    10. }
    11. }
    12. return bst;
    13. }
    14. BSTree SearchBST(BSTree bst,int key) //查找关键值key的节点,并且返回这个节点
    15. {
    16. if(bst == NULL)
    17. return NULL;
    18. else if(key == bst->key)
    19. return bst;
    20. else if(key > bst->key)
    21. return SearchBST(bst->rchild,key);
    22. else
    23. return SearchBST(bst->lchild,key);
    24. }
    25. BSTree InsertBST_key(BSTree bst,int key) //搜寻一个关键值,如果没有就插入
    26. {
    27. BSTree s;
    28. s = SearchBST(bst,key);
    29. if(s)
    30. printf("该节点已经存在.");
    31. else{
    32. s = (BSTree)malloc(sizeof(BTNode));
    33. s->key = key;
    34. s->lchild = NULL;
    35. s->rchild = NULL;
    36. s = InsertBST(bst,s);
    37. }
    38. return s;
    39. }

    查找二叉排序树指定节点的双亲

    1. BSTree SearchBST_F(BSTree bst,int key,BSTree *F) //F存储key关键值节点的双亲节点,函数返回key关键值节点.
    2. {
    3. if(bst == NULL)
    4. return NULL;
    5. if(key == bst->key)
    6. return bst;
    7. else{
    8. *F = bst;
    9. if(key < bst->key)
    10. return SearchBST_F(bst->lchild,key,F);
    11. else
    12. return SearchBST_F(bst->rchild,key,F);
    13. }
    14. }

     删除二叉排序树中某个节点:

    对于删除二叉排序树的节点,我们有必要花大功夫来讨论一下。

    对于删除二叉排序树的某个节点,大致有以下四种情况:

    假设我们要删除的节点指定为P

    1.P节点的左右子树都为空

    此时删除P节点,只需要P节点的父节点的左/右子树赋值NULL,并且free掉P节点即可。

    值得注意的是,还有一种特殊情况,那就是P节点本身就是根节点,也就是这个树只有P节点一个

    节点。

    那么此时,我们只需要返回NULL,并且free掉P节点即可。

    2.P节点的左子树为空

    在这种情况下,我们注意到P的右子树不是空的,如下图所示:

    此时我们只需要令P节点的父节点C的右子树/左子树为P的右子树即可。

    不过值得注意的是,此时仍有可能P是根节点,此时我们需要令根节点 = p的右子树,并且free掉p

    节点即可。

    3.P节点的右子树为空

    此时我们注意到,这种情况根情况2(P节点的左子树为空)非常相似。

    此时我们只需要令P的父节点C的左/右子树等于P的左子树即可。

    不过此时P节点仍有可能作为根节点出现,此时我们只需要令根节点等于P的左子树即可。

    4.P节点的左右子树都不为空

    这种情况无疑是最复杂的一种情况,因为此时我们要牵扯一个大小的排序。

    因此,我们可以令P节点的Key值等于P节点的直接前驱(直接后驱)的Key值,之后删掉直接前驱(直

    接后驱)即可。

    注意到此时的P节点的直接前驱是G(即P节点的左子树的最右侧的一个节点)。

    那么此时我们可以令P节点的Key值等于G节点的Key值,同时free掉G节点即可完成操作。

    不过,比较重要的一点是,G节点的左子树不一定为空此时我们仍需要让G节点的节点的右子

    等于G节点的左子树

    注意到,当P节点作为根结点的时候并不会出现特殊的情况,但是当P节点的前驱节点就是P的左子

    ,我们需要另外的讨论,如下图所示:

    注意到此时P的直接前驱节点就是D,但是如果我们直接删除D,那么D的左子树此时应该给P的

    子树。

    注意到P也是D的一个父节点,P同时还是D的一个直接后继节点,此时就是一种特殊情况,需要让

    P左子树等于D左子树,而不是D父节点右子树等于D左子树!!!

    代码实现:

    1. BSTree SearchBST_F(BSTree bst,int key,BSTree *F) //查找Key值节点的父节点,*F存储父节点,函数返回Key节点
    2. {
    3. if(bst == NULL)
    4. return NULL;
    5. if(bst->key == key)
    6. return bst;
    7. else{
    8. *F = bst;
    9. if(bst->key > key)
    10. return SearchBST_F(bst->lchild,key,F);
    11. else
    12. return SearchBST_F(bst->rchild,key,F);
    13. }
    14. }
    15. BSTree DeleteBST(BSTree bst,BSTree p,BSTree f)
    16. {
    17. BSTree par,s;
    18. int kind;
    19. if(!p->lchild && !p->rchild) //左右子树全为空
    20. kind = 1;
    21. else if(!p->lchild) //左子树为空
    22. kind = 2;
    23. else if(!p->rchild) //右子树为空
    24. kind = 3;
    25. else //左右子树都不为空
    26. kind = 4;
    27. switch(kind){
    28. case 1:
    29. if(!f) //没有父节点,p是根节点,
    30. return NULL;
    31. else{
    32. if(f->lchild == p)
    33. f->lchild = NULL;
    34. else
    35. f->rchild = NULL;
    36. free(p);
    37. }
    38. break;
    39. case 2:
    40. if(!f) //p是根节点
    41. bst = bst->rchild;
    42. else{
    43. if(p == f->lchild)
    44. f->lchild = p->rchild;
    45. else
    46. f->rchild = p->rchild;
    47. free(p);
    48. }
    49. break;
    50. case 3:
    51. if(!f) //p是根节点
    52. bst = bst->lchild;
    53. else{
    54. if(p == f->lchild)
    55. f->lchild = bst->lchild;
    56. else
    57. f->rchild = bst->lchild;
    58. }
    59. free(p);
    60. break;
    61. case 4:
    62. par = p; //p节点前驱指针par
    63. s = p->lchild; //用来遍历p的直接前驱节点(左子树的最右侧)
    64. while(s->rchild != NULL){ //结束条件是s的右子树为空,此时s就是p的直接前驱节点
    65. par = s;
    66. s = s->rchild;
    67. }
    68. p->key = s->key; //令p节点的值为s节点的值
    69. if(par == p) //特殊情况,s节点刚好是p的左子树
    70. par->lchild = s->lchild;
    71. else
    72. par->rchild = s->lchild; //par的右子树需要等于s节点的左子树
    73. free(s); //释放p节点的直接前驱s
    74. break;
    75. }
    76. return bst;
    77. }
    78. BSTree SearchDeleteBST(BSTree bst,int key)
    79. {
    80. BSTree f = NULL,p;
    81. p = SearchBST_F(bst,key,&f);
    82. if(p){
    83. bst = DeleteBST(bst,p,f);
    84. }
    85. else
    86. printf("该节点不存在.\n");
    87. return bst;
    88. }

    二叉排序树的所有代码汇总: 

    1. #include
    2. #include
    3. typedef int ElemType;
    4. typedef struct BSNode{
    5. ElemType key;
    6. struct BSNode *lchild,*rchild;
    7. }BSNode,*BSTree;
    8. BSTree SearchBST(BSTree bst,BSTree s)
    9. {
    10. if(bst == NULL)
    11. bst = s;
    12. else{
    13. if(bst->key > s->key)
    14. bst->lchild = SearchBST(bst->lchild,s);
    15. if(bst->key < s->key)
    16. bst->rchild = SearchBST(bst->rchild,s);
    17. }
    18. return bst;
    19. }
    20. BSTree CreateBSTree()
    21. {
    22. int key;
    23. BSTree bst = NULL;
    24. printf("请输入节点关键值,输入-1结束.\n");
    25. while(1){
    26. scanf("%d",&key);
    27. if(key != -1){
    28. BSTree s = (BSTree)malloc(sizeof(BSNode));
    29. s->key = key;
    30. s->lchild = NULL;
    31. s->rchild = NULL;
    32. bst = SearchBST(bst,s);
    33. printf("创建节点成功.\n");
    34. }
    35. else
    36. break;
    37. }
    38. return bst;
    39. }
    40. void PostTraverse(BSTree bst)
    41. {
    42. if(bst){
    43. PostTraverse(bst->lchild);
    44. printf("%d ",bst->key);
    45. PostTraverse(bst->rchild);
    46. }
    47. }
    48. BSTree SearchBST_F(BSTree bst,int key,BSTree *F) //查找Key值节点的父节点,*F存储父节点,函数返回Key节点
    49. {
    50. if(bst == NULL)
    51. return NULL;
    52. if(bst->key == key)
    53. return bst;
    54. else{
    55. *F = bst;
    56. if(bst->key > key)
    57. return SearchBST_F(bst->lchild,key,F);
    58. else
    59. return SearchBST_F(bst->rchild,key,F);
    60. }
    61. }
    62. BSTree DeleteBST(BSTree bst,BSTree p,BSTree f)
    63. {
    64. BSTree par,s;
    65. int kind;
    66. if(!p->lchild && !p->rchild) //左右子树全为空
    67. kind = 1;
    68. else if(!p->lchild) //左子树为空
    69. kind = 2;
    70. else if(!p->rchild) //右子树为空
    71. kind = 3;
    72. else //左右子树都不为空
    73. kind = 4;
    74. switch(kind){
    75. case 1:
    76. if(!f) //没有父节点,p是根节点,
    77. return NULL;
    78. else{
    79. if(f->lchild == p)
    80. f->lchild = NULL;
    81. else
    82. f->rchild = NULL;
    83. free(p);
    84. }
    85. break;
    86. case 2:
    87. if(!f) //p是根节点
    88. bst = bst->rchild;
    89. else{
    90. if(p == f->lchild)
    91. f->lchild = p->rchild;
    92. else
    93. f->rchild = p->rchild;
    94. free(p);
    95. }
    96. break;
    97. case 3:
    98. if(!f) //p是根节点
    99. bst = bst->lchild;
    100. else{
    101. if(p == f->lchild)
    102. f->lchild = bst->lchild;
    103. else
    104. f->rchild = bst->lchild;
    105. }
    106. free(p);
    107. break;
    108. case 4:
    109. par = p; //p节点前驱指针par
    110. s = p->lchild; //用来遍历p的直接前驱节点(左子树的最右侧)
    111. while(s->rchild != NULL){ //结束条件是s的右子树为空,此时s就是p的直接前驱节点
    112. par = s;
    113. s = s->rchild;
    114. }
    115. p->key = s->key; //令p节点的值为s节点的值
    116. if(par == p) //特殊情况,s节点刚好是p的左子树
    117. par->lchild = s->lchild;
    118. else
    119. par->rchild = s->lchild; //par的右子树需要等于s节点的左子树
    120. free(s); //释放p节点的直接前驱s
    121. break;
    122. }
    123. return bst;
    124. }
    125. BSTree SearchDeleteBST(BSTree bst,int key)
    126. {
    127. BSTree f = NULL,p;
    128. p = SearchBST_F(bst,key,&f);
    129. if(p){
    130. bst = DeleteBST(bst,p,f);
    131. }
    132. else
    133. printf("该节点不存在.\n");
    134. return bst;
    135. }
    136. int main()
    137. {
    138. BSTree bst;
    139. bst = CreateBSTree();
    140. SearchDeleteBST(bst,5);
    141. PostTraverse(bst);
    142. return 0;
    143. }
  • 相关阅读:
    NFS从入门到精通再到放弃
    批量重命名与翻译文件技巧大揭秘
    Android学习笔记 63. 添加一个ScrollView
    JavaWeb项目(三)
    Python Opencv实践 - FAST关键点检测
    一个案例搞懂工厂模式和单例模式
    Java还是要系统学习,阿里面试失败的经验总结,最终获字节offer
    【C++】-- STL之unordered_map/unordered_set详解
    基于单片机的太阳能热水器控制系统设计
    day34(arguments 原型对象prototype apply和call 以及 柯里化函数)
  • 原文地址:https://blog.csdn.net/zheshiyangyang/article/details/134383064