当前位置:   article > 正文

二叉排序树的创建,插入和删除(C++完整代码)_建立一个四层二叉树,有排序插入删除的功能

建立一个四层二叉树,有排序插入删除的功能

一、二叉排序树(二叉查找树)的概念

(1)若左子树非空,则左子树上所有结点的值均小于根节点的值

(2)若右子树非空,则右子树上所有结点的值均大于根节点的值

(3)左右子树分别也是一棵二叉排序树

tip:可以是一棵空树

二、二叉排序树的判别

(1)因为二叉排序树的中序遍历是一个有序递增序列,可以对已经建立的二叉树进行中序遍历,如果满足则判断是

三、二叉排序树的创建(creat、insert)

树结点的结构体:

struct tree{
    int data;
    struct tree* lchild;
    struct tree* rchild;
};

  1. //递归创建结点
  2. void Creat(int a,tree* &T){
  3. if(T==NULL){
  4. T=new tree;
  5. T->data=a;
  6. T->lchild=NULL;
  7. T->rchild=NULL;
  8. }
  9. else if(a>T->data){
  10. Creat(a,T->rchild);
  11. }
  12. else{
  13. Creat(a,T->lchild);
  14. }
  15. }
  16. //传入数组,一次性插入
  17. void Insert(tree* &T,int A[],int len){
  18. for(int i=0;i<=len;i++){
  19. Creat(A[i],T);
  20. }
  21. }

四、二叉排序树的插入

  1. //查找指定结点(输出当前结点是否存在),如果没有就插入
  2. void find(tree* &T,int a){
  3. tree* K=T; //T指针指向二叉排序树的根节点,K为工作指针
  4. tree* pre; //pre指向当前工作指针的上一个结点,用于插入确定插入位置
  5. while(K!=NULL&&a!=K->data){
  6. if(a>K->data){
  7. pre=K;
  8. K=K->rchild;
  9. }else{
  10. pre=K;
  11. K=K->lchild;
  12. }
  13. }
  14. if(K==NULL){
  15. tree* P; //工作指针
  16. P=new tree;
  17. P->data=a;
  18. if(P->data>pre->data){
  19. pre->rchild=P;
  20. P->lchild=NULL;
  21. P->rchild=NULL;
  22. }
  23. else{
  24. pre->lchild=P;
  25. P->lchild=NULL;
  26. P->rchild=NULL;
  27. }
  28. cout<<"不存在,已插入 "<<a<<" 这个结点"<<endl;
  29. }else{
  30. cout<<"存在"<<endl;
  31. }
  32. }

五、二插排序树的删除

  1. //删除某一结点,若不存在则提示
  2. //①当该结点是叶子结点时,直接删除
  3. //②当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替他的位置
  4. //③当左右孩子都存在时找中序遍历的下一个(或上一个)结点代替其位置
  5. void delect(tree* &T,int a){
  6. //首先找到要删除的结点
  7. tree* Pre;
  8. tree* P=T; //定义工作指针
  9. while(P!=NULL&&a!=P->data){ //这两个判定条件不能颠倒
  10. if(a>P->data){
  11. Pre=P;
  12. P=P->rchild;
  13. }else{
  14. Pre=P;
  15. P=P->lchild;
  16. }
  17. }
  18. if(P==NULL){
  19. cout<<"要删除的结点不存在"<<endl;
  20. }else{
  21. // ①当该结点是叶子结点时,直接删除
  22. if(P->lchild==NULL&&P->rchild==NULL){
  23. if(P->data>Pre->data){
  24. Pre->rchild=NULL;
  25. }else{
  26. Pre->lchild=NULL;
  27. }
  28. cout<<"已删除 "<<a<<endl;
  29. }
  30. //②当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替他的位置
  31. if((P->lchild!=NULL&&P->rchild==NULL)||(P->rchild!=NULL&&P->lchild==NULL)){
  32. if(P->data>Pre->data){
  33. if(P->lchild!=NULL){
  34. Pre->rchild=P->lchild;
  35. }else{
  36. Pre->rchild=P->rchild;
  37. }
  38. }
  39. if(P->data<Pre->data){
  40. if(P->lchild!=NULL){
  41. Pre->lchild=P->lchild;
  42. }else{
  43. Pre->lchild=P->rchild;
  44. }
  45. }
  46. cout<<"已删除 "<<a<<endl;
  47. }
  48. //③当左右孩子都存在时找中序遍历的下一个(或上一个结点)结点代替其位置 ,这里采用中序遍历上一个结点来代替
  49. if(P->lchild!=NULL&&P->rchild!=NULL){
  50. tree* Q=P->lchild; //工作指针
  51. tree* Pre2; //用于记录最终遍历到的结点的前序结点,用于后期连接
  52. while(Q->rchild){
  53. Pre2=Q;
  54. Q=Q->rchild;
  55. }
  56. P->data=Q->data;
  57. if(P!=Pre2){
  58. Pre2->rchild=Q->lchild;
  59. }else{
  60. Pre2->lchild=Q->lchild;
  61. }
  62. delete(Q);
  63. cout<<"已删除 "<<a<<endl;
  64. }
  65. }
  66. }

这里对第三种情况作一些补充:

注意:这里采用的是找左子树的最右下结点来代替要删除的结点(对于王道书上的用中序遍历的下一个结点的方法是一样的,后面也会附上代码)

第一步:找到左子树的最右下结点(这里用到了一个工作指针Q)

无非只有下面几种情况:

 

由此我们可以王道书上的版本,这里只给代码,分析和上面类似

  1. if(P->lchild!=NULL&&P->rchild!=NULL){
  2. tree* Q=P->rchild;
  3. tree* Pre2;
  4. while(Q->lchild){
  5. Pre2=Q;
  6. Q=Q->lchild;
  7. }
  8. P->data=Q->data;
  9. if(P!=Pre2){
  10. Pre2->lchild=Q->rchild;
  11. }else{
  12. Pre2->rchild=Q->rchild;
  13. }
  14. delete(Q);
  15. }

六、完整代码(可以运行,两种方法都有)

  1. #include<iostream>
  2. using namespace std;
  3. struct tree{
  4. int data;
  5. struct tree* lchild;
  6. struct tree* rchild;
  7. };
  8. //建立创建,传入一个完整的数组
  9. void Creat(int a,tree* &T){
  10. if(T==NULL){
  11. T=new tree;
  12. T->data=a;
  13. T->lchild=NULL;
  14. T->rchild=NULL;
  15. }
  16. else if(a>T->data){
  17. Creat(a,T->rchild);
  18. }
  19. else{
  20. Creat(a,T->lchild);
  21. }
  22. }
  23. //传入数组,一次性插入
  24. void Insert(tree* &T,int A[],int len){
  25. for(int i=0;i<=len;i++){
  26. Creat(A[i],T);
  27. }
  28. }
  29. //中序遍历
  30. void midorder(tree* T){
  31. if(T!=NULL){
  32. midorder(T->lchild);
  33. cout<<T->data<<" ";
  34. midorder(T->rchild);
  35. }
  36. }
  37. //判断是否是二叉排序树
  38. //对树进行中序遍历,然后判断是否有序递增
  39. //查找指定结点(输出当前结点是否存在),如果没有就插入
  40. void find(tree* &T,int a){
  41. tree* K=T; //T指针指向二叉排序树的根节点,K为工作指针
  42. tree* pre; //pre指向当前工作指针的上一个结点,用于插入确定插入位置
  43. while(K!=NULL&&a!=K->data){
  44. if(a>K->data){
  45. pre=K;
  46. K=K->rchild;
  47. }else{
  48. pre=K;
  49. K=K->lchild;
  50. }
  51. }
  52. if(K==NULL){
  53. tree* P; //工作指针
  54. P=new tree;
  55. P->data=a;
  56. if(P->data>pre->data){
  57. pre->rchild=P;
  58. P->lchild=NULL;
  59. P->rchild=NULL;
  60. }
  61. else{
  62. pre->lchild=P;
  63. P->lchild=NULL;
  64. P->rchild=NULL;
  65. }
  66. cout<<"不存在,已插入 "<<a<<" 这个结点"<<endl;
  67. }else{
  68. cout<<"存在"<<endl;
  69. }
  70. }
  71. //删除某一结点,若不存在则提示
  72. //①当该结点是叶子结点时,直接删除
  73. //②当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替他的位置
  74. //③当左右孩子都存在时找中序遍历的下一个(或上一个)结点代替其位置
  75. void delect(tree* &T,int a){
  76. //首先找到要删除的结点
  77. tree* Pre;
  78. tree* P=T; //定义工作指针
  79. while(P!=NULL&&a!=P->data){ //这两个判定条件不能颠倒
  80. if(a>P->data){
  81. Pre=P;
  82. P=P->rchild;
  83. }else{
  84. Pre=P;
  85. P=P->lchild;
  86. }
  87. }
  88. if(P==NULL){
  89. cout<<"要删除的结点不存在"<<endl;
  90. }else{
  91. // ①当该结点是叶子结点时,直接删除
  92. if(P->lchild==NULL&&P->rchild==NULL){
  93. if(P->data>Pre->data){
  94. Pre->rchild=NULL;
  95. }else{
  96. Pre->lchild=NULL;
  97. }
  98. cout<<"已删除 "<<a<<endl;
  99. }
  100. //②当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替他的位置
  101. if((P->lchild!=NULL&&P->rchild==NULL)||(P->rchild!=NULL&&P->lchild==NULL)){
  102. if(P->data>Pre->data){
  103. if(P->lchild!=NULL){
  104. Pre->rchild=P->lchild;
  105. }else{
  106. Pre->rchild=P->rchild;
  107. }
  108. }
  109. if(P->data<Pre->data){
  110. if(P->lchild!=NULL){
  111. Pre->lchild=P->lchild;
  112. }else{
  113. Pre->lchild=P->rchild;
  114. }
  115. }
  116. cout<<"已删除 "<<a<<endl;
  117. }
  118. //③当左右孩子都存在时找中序遍历的下一个(或上一个结点)结点代替其位置 ,这里采用中序遍历上一个结点来代替
  119. // if(P->lchild!=NULL&&P->rchild!=NULL){
  120. // tree* Q=P->lchild; //工作指针
  121. // tree* Pre2; //用于记录最终遍历到的结点的前序结点,用于后期连接
  122. // while(Q->rchild){
  123. // Pre2=Q;
  124. // Q=Q->rchild;
  125. // }
  126. // P->data=Q->data;
  127. // if(P!=Pre2){
  128. // Pre2->rchild=Q->lchild;
  129. // }else{
  130. // Pre2->lchild=Q->lchild;
  131. // }
  132. // delete(Q);
  133. // cout<<"已删除 "<<a<<endl;
  134. // }
  135. if(P->lchild!=NULL&&P->rchild!=NULL){
  136. tree* Q=P->rchild;
  137. tree* Pre2;
  138. while(Q->lchild){
  139. Pre2=Q;
  140. Q=Q->lchild;
  141. }
  142. P->data=Q->data;
  143. if(P!=Pre2){
  144. Pre2->lchild=Q->rchild;
  145. }else{
  146. Pre2->rchild=Q->rchild;
  147. }
  148. delete(Q);
  149. cout<<"已删除 "<<a<<endl;
  150. }
  151. }
  152. }
  153. int main(){
  154. tree* T=NULL;
  155. int A[]={23,89,65,12,17,3,9,90,21,63,71};
  156. Insert(T,A,10);
  157. midorder(T);
  158. delect(T,89);
  159. midorder(T);
  160. find(T,89);
  161. midorder(T);
  162. return 0;
  163. }

结语:感谢观看,有什么问题望指正

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/709673
推荐阅读
相关标签
  

闽ICP备14008679号