【数据结构】二叉树、AVL树

 

二叉树

二叉树是每个结点最多有两个子树的有序树。通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。

二叉树有几点重要的性质:

  •  性质1:在二叉树的第 i 层上至多有2i-1 个结点。 (i≥1)
  • 性质2:深度为 k 的二叉树上至多含2k-1 个结点(k≥1)。
  • 性质3:对任何一棵二叉树,若它含有n0 个叶子结点、n2 个度为 2 的结点,则必存在关系式:n0 = n2+1。
  • 性质4:具有 n 个结点的完全二叉树的深度为log2n+1
  • 性质5:若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点:
    (1) 若 i=1,则该结点是二叉树的根,无双亲,否则,编号为i/2 的结点为其双亲结点;
    (2) 若 2i>n,则该结点无左孩子,否则,编号为 2i 的结点为其左孩子结点;
    (3) 若 2i+1>n,则该结点无右孩子结点,否则,编号为2i+1 的结点为其右孩子结点。

采用链式存储结构实现二叉树

链式存储二叉树

 

1.首先我们要构造可以表示二叉树的节点的结构 Binary_node

2.构造类二叉树 Binary_tree,并编写其几个基本的成员函数:

Empty()-检查树是否为空;clear()-将树清空;size()-得到树的大小;leaf_count()-得到叶子数目;height()-得到树高;

以及几个重要的成员函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Binary_tree(const Binary_tree<Entry>&original); 拷贝构造成员函数  
  2. Binary_tree &operator=(const Binary_tree<Entry>&original);重载赋值操作符  
  3. ~Binary_tree();析构函数  

 

3.分别编写遍历算法的成员函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void inorder(void(*visit)(Entry &)); 中序遍历(LVR)  
  2. void preorder(void(*visit)(Entry &)); 前序遍历(VLR)  
  3. void postorder(void(*visit)(Entry &)); 后续遍历(LRV)  

因为二叉树的性质,三种遍历算法我们都用递归实现,所以分别编写其递归函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void recursive_inorder(Binary_node<Entry>*sub_root,void (*visit)(Entry &));  
  2. void recursive_preorder(Binary_node<Entry>*sub_root,void(*visit)(Entry &));  
  3. void recursive_postorder(Binary_node<Entry>*sub_root,void(*visit)(Entry &));  

 

4.作为辅助,我们再编写一个print_tree的函数,用以以括号表示法输出
同样使用递归,编写递归函数void recursive_print(Binary_node<Entry>*sub_root);
几个重要的函数代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. template<class Entry>  
  2. void Binary_tree<Entry>::inorder(void(*visit)(Entry &))  
  3. //Post: The tree has been traversed in inorder sequence  
  4. //Uses: The function recursive_inorder  
  5. {  
  6.     recursive_inorder(root,visit);  
  7. }  
  8.   
  9. template<class Entry>  
  10. void Binary_tree<Entry>::recursive_inorder(Binary_node<Entry>*sub_root,void(*visit)(Entry &))  
  11. //Pre:  sub_root is either NULL or points to a subtree of the Binary_tree  
  12. //Post: The subtree has been traversed in inorder sequence  
  13. //Uses: The function recursive_inorder recursively  
  14. {  
  15.     if(sub_root!=NULL){  
  16.         recursive_inorder(sub_root->left,visit);  
  17.         (*visit)(sub_root->data);  
  18.         recursive_inorder(sub_root->right,visit);  
  19.     }  
  20. }  
  21.   
  22. template<class Entry>  
  23. void Binary_tree<Entry>::preorder(void(*visit)(Entry &))  
  24. //Post: The tree has been traversed in preorder sequence  
  25. //Uses: The function recursive_preorder  
  26. {  
  27.     recursive_preorder(root,visit);  
  28. }  
  29.   
  30. template<class Entry>  
  31. void Binary_tree<Entry>::recursive_preorder(Binary_node<Entry>*sub_root,void(*visit)(Entry &))  
  32. //Pre:  sub_root is either NULL or points to a subtree of the Binary_tree  
  33. //Post: The subtree has been traversed in preorder sequence  
  34. //Uses: The function recursive_preorder recursively  
  35. {  
  36.     if(sub_root!=NULL){  
  37.         (*visit)(sub_root->data);  
  38.         recursive_preorder(sub_root->left,visit);  
  39.         recursive_preorder(sub_root->right,visit);  
  40.     }  
  41. }  
  42.   
  43. template<class Entry>  
  44. void Binary_tree<Entry>::postorder(void(*visit)(Entry &))  
  45. //Post: The tree has been traversed in postorder sequence  
  46. //Uses: The function recursive_postorder  
  47. {  
  48.     recursive_postorder(root,visit);  
  49. }  
  50.   
  51. template<class Entry>  
  52. void Binary_tree<Entry>::recursive_postorder(Binary_node<Entry>*sub_root,void(*visit)(Entry &))  
  53. //Pre:  sub_root is either NULL or points to a subtree fo the Binary_tree  
  54. //Post: The subtree has been traversed in postorder sequence  
  55. //Uses: The function recursive_postorder recursively  
  56. {  
  57.     if(sub_root!=NULL){  
  58.         recursive_postorder(sub_root->left,visit);  
  59.         recursive_postorder(sub_root->right,visit);  
  60.         (*visit)(sub_root->data);  
  61.     }  
  62. }  
  63. template<class Entry>  
  64. void Binary_tree<Entry>::print_tree()  
  65. {  
  66.     recursive_print(root);  
  67.     cout<<endl;  
  68. }  
  69.   
  70. template<class Entry>  
  71. void Binary_tree<Entry>::recursive_print(Binary_node<Entry>*sub_root)  
  72. {  
  73.     if(sub_root!=NULL){  
  74.         cout<<sub_root->data;  
  75.         cout<<"(";  
  76.         recursive_print(sub_root->left);  
  77.         cout<<",";  
  78.         recursive_print(sub_root->right);  
  79.         cout<<")";  
  80.     }  
  81.   
  82. }  
  83. //其他函数见源码  


程序结果

插入二叉树并实现中序、前序和后序遍历

 

AVL树

AVL树得名于其发明者G.M.Adelson-Velsky和E.M.Landis。AVL树是一个各结点具有平衡高度的扩展的二叉搜索树。在AVL树中,任一结点的两个子树的高度差最多为1,AVL树的高度不会超过1,AVL树既有二叉搜索树的搜索效率又可以避免二叉搜索树的最坏情况(退化树)出现。

AVL树的表示与二叉搜索树类似,其操作基本相同,但插入和删除方法除外,因为它们必须不断监控结点的左右子树的相对高度,这也正是AVL树的优势所在。

实现AVL树的相关运算

1、首先我们修改结构Binary_node,增加Balance_factor用以表示节点平衡情况

2、从二叉搜索树中派生出AVL树,编写其关键的插入和删除成员函数。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Error_code insert(const Record &new_data);  
  2. Error_code remove(const Record &old_data);  

3、入和删除函数我们都用递归实现
编写递归函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Error_code avl_insert(Binary_node<Record>* &sub_root,   
  2.                        const Record &new_data,bool &taller);  
  3. Error_code avl_remove(Binary_node<Record>* &sub_root,  
  4.                        const Record &target,bool &shorter);  

以及几个重要的调用函数: 
左旋右旋函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void rotate_left(Binary_node<Record>* &sub_root);  
  2. void rotate_right(Binary_node<Record>* &sub_root);  

两次旋转的左右平衡函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void right_balance(Binary_node<Record>* &sub_root);  
  2. void left_balance(Binary_node<Record>* &sub_root);  

删除函数还要分别编写删除左树和删除右树的递归函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Error_code avl_remove_right(Binary_node<Record>&sub_root,  
  2.                             const Record &target,bool &shorter);  
  3. Error_code avl_remove_left(Binary_node<Record>*&sub_root,  
  4.                             const Record &target,bool &shorter);  

 

4、个重要的成员函数代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. template<class Record>  
  2. Error_code AVL_tree<Record>::insert(const Record &new_data)  
  3. //Post: If the key of new_data is already in the AVL_tree, a code of duplicate_error  
  4. //      is returned. Otherwise, a code of success is returned and the Record  
  5. //      new_data is inserted into the tree in such a way that the properties of an  
  6. //      AVL tree are preserved.  
  7. {  
  8.     bool taller;  
  9.     return avl_insert(root,new_data,taller);  
  10. }  
  11.   
  12. template<class Record>  
  13. Error_code AVL_tree<Record>::avl_insert(Binary_node<Record>* &sub_root, const Record &new_data,bool &taller)  
  14. //Pre:  sub_root is either NULL or points to a subtree of the AVL tree  
  15. //Post: If the key of new_data is already in the subtree, a code of duplicate_error  
  16. //      is returned. Otherwise, a code of success is returned and the Record   
  17. //      new_data is inserted into the subtree in such a way that the properties of   
  18. //      an AVL tree have been preserved. If the subtree is increase in height, the  
  19. //      parameter taller is set to true; otherwise it is set to false  
  20. //Uses: Methods of struct AVL_node; functions avl_insert recursively, left_balance, and right_balance  
  21. {  
  22.     Error_code result=success;  
  23.     if(sub_root==NULL){  
  24.         sub_root=new Binary_node<Record>(new_data);  
  25.         taller=true;  
  26.     }  
  27.     else if(new_data==sub_root->data){  
  28.         result=duplicate_error;  
  29.         taller=false;  
  30.     }  
  31.     else if(new_data<sub_root->data){//Insert in left subtree  
  32.         result=avl_insert(sub_root->left,new_data,taller);  
  33.         if(taller==true)  
  34.             switch(sub_root->get_balance()){//Change balance factors  
  35.             case left_higher:  
  36.                 left_balance(sub_root);  
  37.                 taller=false;  
  38.                 break;  
  39.             case equal_height:  
  40.                 sub_root->set_balance(left_higher);  
  41.                 break;  
  42.             case right_higher:  
  43.                 sub_root->set_balance(equal_height);  
  44.                 taller=false;  
  45.                 break;  
  46.         }  
  47.     }  
  48.     else{        //Insert in right subtree  
  49.         result=avl_insert(sub_root->right,new_data,taller);  
  50.         if(taller==true)  
  51.             switch(sub_root->get_balance()){  
  52.             case left_higher:  
  53.                 sub_root->set_balance(equal_height);  
  54.                 taller=false;  
  55.                 break;  
  56.             case equal_height:  
  57.                 sub_root->set_balance(right_higher);  
  58.                 break;  
  59.             case right_higher:  
  60.                 right_balance(sub_root);  
  61.                 taller=false//Rebalancing always shortens the tree  
  62.                 break;  
  63.         }  
  64.     }  
  65.     return result;  
  66. }  
  67.   
  68. template<class Record>  
  69. void AVL_tree<Record>::right_balance(Binary_node<Record>* &sub_root)  
  70. //Pre:  sub_root points to a subtree of an AVL_tree that is doubly unbalanced  
  71. //      on the right  
  72. //Post: The AVL properties have been restored to the subtree  
  73. {  
  74.     Binary_node<Record>* &right_tree=sub_root->right;  
  75.     switch(right_tree->get_balance()){  
  76.     case right_higher:  
  77.         sub_root->set_balance(equal_height);  
  78.         right_tree->set_balance(equal_height);  
  79.         rotate_left(sub_root);  
  80.         break;  
  81.     case equal_height:  
  82.         cout<<"WARNING: program error detected in right_balance "<<endl;  
  83.     case left_higher:  
  84.         Binary_node<Record>*sub_tree=right_tree->left;  
  85.         switch(sub_tree->get_balance()){  
  86.         case equal_height:  
  87.             sub_root->set_balance(equal_height);  
  88.             right_tree->set_balance(equal_height);  
  89.             break;  
  90.         case left_higher:  
  91.             sub_root->set_balance(equal_height);  
  92.             right_tree->set_balance(right_higher);  
  93.         case right_higher:  
  94.             sub_root->set_balance(left_higher);  
  95.             right_tree->set_balance(equal_height);  
  96.             break;  
  97.         }  
  98.         sub_tree->set_balance(equal_height);  
  99.         rotate_right(right_tree);  
  100.         rotate_left(sub_root);  
  101.         break;  
  102.     }  
  103. }  
  104.   
  105. template<class Record>  
  106. void AVL_tree<Record>::left_balance(Binary_node<Record>* &sub_root)  
  107. {  
  108.     Binary_node<Record>* &left_tree=sub_root->left;  
  109.     switch(left_tree->get_balance()){  
  110.     case left_higher:  
  111.         sub_root->set_balance(equal_height);  
  112.         left_tree->set_balance(equal_height);  
  113.         rotate_right(sub_root);  
  114.         break;  
  115.     case equal_height:  
  116.         cout<<"WARNING: program error detected in left_balance"<<endl;  
  117.     case right_higher:  
  118.         Binary_node<Record>*sub_tree=left_tree->right;  
  119.         switch(sub_tree->get_balance()){  
  120.         case equal_height:  
  121.             sub_root->set_balance(equal_height);  
  122.             left_tree->set_balance(equal_height);  
  123.             break;  
  124.         case right_higher:  
  125.             sub_root->set_balance(equal_height);  
  126.             left_tree->set_balance(left_higher);  
  127.             break;  
  128.         case left_higher:  
  129.             sub_root->set_balance(right_higher);  
  130.             left_tree->set_balance(equal_height);  
  131.             break;  
  132.         }  
  133.         sub_tree->set_balance(equal_height);  
  134.         rotate_left(left_tree);  
  135.         rotate_right(sub_root);  
  136.         break;  
  137.     }  
  138. }  
  139.   
  140. template<class Record>  
  141. void AVL_tree<Record>::rotate_left(Binary_node<Record>* &sub_root)  
  142. //Pre:  sub_root points to a subtree of the AVL_tree. This subtree has   
  143. //      a nonempty right subtree.  
  144. //Post: sub_root is reset to point to its former right child, and the   
  145. //      former sub_root node is the left child of the new sub_root node  
  146. {  
  147.     if(sub_root==NULL||sub_root->right==NULL)//impossible cases  
  148.         cout<<"WARNING: program error detected in rotate_left"<<endl;  
  149.     else{  
  150.         Binary_node<Record>*right_tree=sub_root->right;  
  151.         sub_root->right=right_tree->left;  
  152.         right_tree->left=sub_root;  
  153.         sub_root=right_tree;  
  154.     }  
  155. }  
  156.   
  157. template<class Record>  
  158. void AVL_tree<Record>::rotate_right(Binary_node<Record>*&sub_root)  
  159. {  
  160.     if(sub_root==NULL||sub_root->left==NULL)  
  161.         cout<<"WARNING:program error in detected in rotate_right"<<endl;  
  162.     else{  
  163.         Binary_node<Record>*left_tree=sub_root->left;  
  164.         sub_root->left=left_tree->right;  
  165.         left_tree->right=sub_root;  
  166.         sub_root=left_tree;  
  167.     }  
  168. }  
  169.   
  170. template<class Record>  
  171. Error_code AVL_tree<Record>::remove(const Record &old_data)  
  172. {  
  173.     bool shorter;  
  174.     return avl_remove(root,old_data,shorter);  
  175. }  
  176.   
  177. template<class Record>  
  178. Error_code AVL_tree<Record>::avl_remove(Binary_node<Record>* &sub_root,  
  179.                                         const Record &target,bool &shorter)  
  180. {  
  181.     Binary_node<Record>*temp;  
  182.     if(sub_root==NULL)return fail;  
  183.     else if(target<sub_root->data)  
  184.         return avl_remove_left(sub_root,target,shorter);  
  185.     else if(target>sub_root->data)  
  186.         return avl_remove_right(sub_root,target,shorter);  
  187.     else if(sub_root->left==NULL){//Found target: delete current node  
  188.         temp=sub_root;       //Move right subtree up to delete node  
  189.         sub_root=sub_root->right;  
  190.         delete temp;  
  191.         shorter=true;  
  192.     }  
  193.     else if(sub_root->right==NULL){  
  194.         temp=sub_root;   //Move left subtree up to delete node  
  195.         sub_root=sub_root->left;  
  196.         delete temp;  
  197.         shorter=true;  
  198.     }  
  199.     else if(sub_root->get_balance()==left_higher){  
  200.         //Neither subtree is empty; delete from the taller  
  201.         temp=sub_root->left;//Find predecessor of target and delete if from left tree  
  202.         while(temp->right!=NULL)temp=temp->right;  
  203.         sub_root->data=temp->data;  
  204.         avl_remove_left(sub_root,temp->data,shorter);  
  205.     }  
  206.     else{  
  207.         temp=sub_root->right;  
  208.         while(temp->left!=NULL)temp=temp->left;  
  209.         sub_root->data=temp->data;  
  210.         avl_remove_right(sub_root,temp->data,shorter);  
  211.     }  
  212.     return success;  
  213. }  
  214.   
  215. template<class Record>  
  216. Error_code AVL_tree<Record>::avl_remove_right(Binary_node<Record>  
  217.            *&sub_root,const Record &target,bool &shorter)  
  218. {  
  219.     Error_code result=avl_remove(sub_root->right,target,shorter);  
  220.     if(shorter==true)switch(sub_root->get_balance()){  
  221.         case equal_height:  
  222.             sub_root->set_balance(left_higher);  
  223.             shorter=false;  
  224.             break;  
  225.         case right_higher:  
  226.             sub_root->set_balance(equal_height);  
  227.             break;  
  228.         case left_higher:  
  229.             Binary_node<Record>*temp=sub_root->left;  
  230.             switch(temp->get_balance()){  
  231.             case equal_height:  
  232.                 temp->set_balance(right_higher);  
  233.                 rotate_right(sub_root);  
  234.                 shorter=false;  
  235.                 break;  
  236.             case left_higher:  
  237.                 sub_root->set_balance(equal_height);  
  238.                 temp->set_balance(equal_height);  
  239.                 rotate_right(sub_root);  
  240.                 break;  
  241.             case right_higher:  
  242.                 Binary_node<Record>*temp_right=temp->right;  
  243.                 switch(temp_right->get_balance()){  
  244.                 case equal_height:  
  245.                     sub_root->set_balance(equal_height);  
  246.                     temp->set_balance(equal_height);  
  247.                     break;  
  248.                 case left_higher:  
  249.                     sub_root->set_balance(right_higher);  
  250.                     temp->set_balance(equal_height);  
  251.                     break;  
  252.                 case right_higher:  
  253.                     sub_root->set_balance(equal_height);  
  254.                     temp->set_balance(left_higher);  
  255.                     break;  
  256.                 }  
  257.                 temp_right->set_balance(equal_height);  
  258.                 rotate_left(sub_root->left);  
  259.                 rotate_right(sub_root);  
  260.                 break;  
  261.             }  
  262.     }  
  263.     return result;  
  264. }  
  265.   
  266. template<class Record>  
  267. Error_code AVL_tree<Record>::avl_remove_left(Binary_node<Record>  
  268.            *&sub_root,const Record &target,bool &shorter)  
  269. {  
  270.     Error_code result=avl_remove(sub_root->left,target,shorter);  
  271.     if(shorter==true)  
  272.         switch(sub_root->get_balance()){  
  273.         case equal_height:  
  274.             sub_root->set_balance(right_higher);  
  275.             shorter=false;  
  276.             break;  
  277.         case left_higher:  
  278.             sub_root->set_balance(equal_height);  
  279.             break;  
  280.         case right_higher:  
  281.             Binary_node<Record>*temp=sub_root->right;  
  282.             switch(temp->get_balance()){  
  283.             case equal_height:  
  284.                 temp->set_balance(left_higher);  
  285.                 rotate_right(sub_root);  
  286.                 shorter=false;  
  287.                 break;  
  288.             case right_higher:  
  289.                 sub_root->set_balance(equal_height);  
  290.                 temp->set_balance(equal_height);  
  291.                 rotate_left(sub_root);  
  292.                 break;  
  293.             case left_higher:  
  294.                 Binary_node<Record>*temp_left=temp->left;  
  295.                 switch(temp_left->get_balance()){  
  296.                 case equal_height:  
  297.                     sub_root->set_balance(equal_height);  
  298.                     temp->set_balance(equal_height);  
  299.                     break;  
  300.                 case right_higher:  
  301.                     sub_root->set_balance(left_higher);  
  302.                     temp->set_balance(equal_height);  
  303.                     break;  
  304.                 case left_higher:  
  305.                     sub_root->set_balance(equal_height);  
  306.                     temp->set_balance(right_higher);  
  307.                     break;  
  308.                 }  
  309.                 temp_left->set_balance(equal_height);  
  310.                 rotate_right(sub_root->right);  
  311.                 rotate_left(sub_root);  
  312.                 break;  
  313.             }  
  314.     }  
  315.     return result;  
  316. }  


实验结果

实现如下功能:1)由{4,9,0,1,8,6,3,5,2,7}建AVL树B,并以括号表示法输出;2)删除B中关键字为8和2的结点,输出结果。

 

分析总结

 

采用链式存储结构实现二叉树

  1. 二叉树在插入的时候通过判断待插入数据与根节点数据的大小,若小于根数据,插入左树,反之插入右树(我们规定不许有重复元素);二叉树的存储结构常用于搜索等。但搜索的效率常依赖于树的结构。而树的结构与元素插入顺序有很大关系,用上述方法插入时若插入的元素是有序的,则得到的树与队列几乎没有区别,也起不到优化搜索的目的。
  2. 二叉树的遍历算法最为重要的一点是递归,递归使我们不必关心于具体的遍历每个节点的顺序,而只是将其看做三个部分,即左子树,根节点,右子树,具体子树的遍历仍是调用其递归函数。
    3.在打印树的时候,我写的并不完美,因为对于叶子节点,理想应该不再打印括号,但我通过判断根节点不为空而调用递归函数,即只要节点有元素就会输出(,),还是表达出了树的意思,但并没有想到怎样达到简洁的效果。

实现AVL树的相关运算

  1. AVL树每插入,删除一个节点就会判断树的高度并改变相应节点的平衡因素,每当有节点不再满足AVL树的性质,立即通过旋转得到AVL树
  2. 旋转的函数及其巧妙。而插入和删除元素的函数要考虑的情况非常多,一种情况没有考虑到就可能达不到我们想要的效果,函数的编写需要极大的耐心和对编程语句的熟练掌握。很多地方我是参考书上的,别人的代码我可以理解,但我自己写可能还是会漏掉很多情况。

转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7888562

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值