二叉查找树的概念以及实现 前序、中序和后序递归非递归遍历算法

来源:互联网 发布:机械生命体网络 编辑:程序博客网 时间:2024/05/17 23:28

本文主要介绍二叉查找树以及实现,另外实现前序、中序和后序递归非递归遍历算法。

二叉查找树

概述

     《算法导论》第12章介绍了二叉查找树的主要性质。


二叉查找树(Binary Search Tree),也称二叉搜索树、有序二叉树(orderedbinary tree),排序二叉树(sorted binary tree),具有以下性质:

  1. 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 任意节点的左、右子树也分别为二叉查找树。
  4. 没有键值相等的节点(no duplicate nodes)。

根据二叉查找树的特征可知,采用中序遍历一棵二叉查找树,可以得到树中关键字有小到大的序列

二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合multiset关联数组等。搜索、插入、删除的复杂度等于树高,期望O(log n)、最坏O(n)。

Q:二叉查找树性质与最小堆之间有什么区别?能否利用最小堆的性质在O(n)时间内,按序输出含有n个结点的树中的所有关键字?

二叉查找树:根的左子树小于根,根的右子树大于根。而最小堆:根的左右子树均大于根。

不能。原因是含有n个结点的最小堆的结点key大小是根<左<右或者根<右<左,左右子树是无序的。导致结果就是不能按照树的前中后序遍历在O(n)时间内来有序的输出他们。再看二叉查找树,按照中序遍历,正好是左<根<右,他们是有序的。

 

二叉查找树的查询

查找元素13的过程:


递归伪代码:

TREE_SEARCH(x,k)  if x=NULL or k=key[x]      then return x  if(k<key[x])      then return TREE_SEARCH(left[x],k)   else      then return TREE_SEARCH(right[x],k)

非递归伪代码:

ITERATIVE_TREE_SEARCH(x,k)  while x!=NULL and k!=key[x]      do if k<key[x]              then x=left[x]           else              then x=right[x]   return x


最值的查询

最大值:从根结点开始,沿着各个结点的right指针查找下去,直到遇到NULL时结束。伪代码为:

 

TREE_MAXMUM(x)    while right[x] != NULL         do x= right[x]     return x

最小值:从根结点开始,沿着各个节点的left指针查找下去,直到遇到NULL时结束。伪代码为:

TREE_MINMUM(x)    while left[x] != NULL       dox=left[x]    return x

前驱与后继

前驱:


后继:

 

插入与删除

插入:


伪代码:

TREE_INSERT(T,z)    y = NULL;    x =root[T]    while x != NULL        do y =x            if key[z] < key[x]                 then x=left[x]                 else  x=right[x]     parent[z] =y     if y=NULL        then root[T] =z        else if key[z]>key[y]                   then  keft[y] = z                   else   right[y] =z


 

删除:删除过程相对复杂点,主要为

1、       无子节点:直接删除。上图中,5等直接删除

2、       有左节点:将其子左节点作为父节点的子左节点,删除该节点。上图中,把16转换为18的左节点,删除17。

3、       有右节点:将其子右节点作为父节点的子右节点,删除该节点。上图中,把13转换为6的左节点,删除7。

4、       有左右节点:找到该节点的后继(后继的左节点必然为空,如156,18,其后继的左子树不存在,否则会相矛盾),此时有如下两种情况:


各种遍历算法

前序遍历:先遍历根节点,然后遍历左子树,最后遍历右子树(根左右)。

如下图所示。

http://www.cnblogs.com/Anker/archive/2013/01/27/2878594.html


递归

template<class T>voidbin_search_tree<T>::pre_order_recursive(node<T>* op_node) const{     if(op_node != NULL){         cout<<op_node->elem<<"";         pre_order_recursive(op_node->lchild);         pre_order_recursive(op_node->rchild);     }}

非递归:前序遍历的顺序是根左右,可以借助栈实现。先将根节点root入栈,然后循环判断栈是否为空,非空则将节点出栈。然后将该节点的子右节点入栈,将该节点的子左节点入栈。循环直至为空。

template<class T>voidbin_search_tree<T>::pre_order() const{     if(NULL != root){         stack< node<T>* > s;         node<T> *temp_node = NULL;         s.push(root);         while(!s.empty()){              temp_node = s.top();              cout<<temp_node->elem<<"";              s.pop();              if(NULL != temp_node->rchild)                   s.push(temp_node->rchild);              if(NULL != temp_node->lchild)                   s.push(temp_node->lchild);         }     }}

中序遍历:先遍历左子树,然后访问根结点,最后遍历右子树。(左根右)。


递归:

template<class T>voidbin_search_tree<T>::in_order_recursive(node<T>* op_node) const{     if(op_node != NULL){         in_order_recursive(op_node->lchild);         cout<<op_node->elem<<"";         in_order_recursive(op_node->rchild);     }}

非递归:中序遍历要求顺序是左根右,可借助栈s实现。先将根root入栈,然后从root节点开始各自将子左节点入栈直到空为止。然后将空节点出栈,左子树节点出栈,再将其右节点入栈。循环直至栈为空。

template<class T>voidbin_search_tree<T>::in_order() const{     if(NULL != root){         node<T> *temp_node = NULL;         stack< node<T>* > s;         s.push(root);         while(!s.empty()){              temp_node = s.top();              while(NULL != temp_node){ //左子树节点入栈                   s.push(temp_node->lchild);                   temp_node =temp_node->lchild;              }              s.pop(); //pop empty node              if(!s.empty()){                   temp_node = s.top();                   cout<<temp_node->elem<<"";                   s.pop();                   s.push(temp_node->rchild);              }         }     }}

简洁写法:

template<class T>voidbin_search_tree<T>::in_order() const{     if(NULL != root){         node<T> *temp_node = NULL;         stack< node<T>* > s;         temp_node = root;         while((NULL != temp_node) ||(!s.empty()) ){ //简洁版              if(NULL != temp_node){                   s.push(temp_node);                   temp_node =temp_node->lchild;              }              else{                   temp_node = s.top();                   s.pop();                   cout<<temp_node->elem<<"";                   temp_node =temp_node->rchild;              }         }     }}


后序遍历:先遍历左子树,然后遍历右子树,最后访问根结点。(左右根)。


递归:  

template<class T>voidbin_search_tree<T>::post_order_recursive(node<T>* op_node) const{     if(op_node != NULL){         post_order_recursive(op_node->lchild);         post_order_recursive(op_node->rchild);         cout<<op_node->elem<<"";     }}

后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问。网络上很多版本都是用标记来实现,没怎么看懂。还是下面的思路好!

先将节点P入栈,保证根结点在左孩子和右孩子访问之后才能访问,访问准则:

1、如果P不存在左孩子和右孩子,则可以直接访问它;

2、P存在左孩子(右孩子),但是其左孩子(右孩子)已被访问过,则同样可以直接访问该结点。

3、若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

非递归:

template<class T>void bin_search_tree<T>::post_order()const{     if(NULL != root){         stack<node<T>*> s;         node<T> *pre=NULL;//前一次访问节点,         node<T> *cur=NULL;//当前节点         s.push(root);         while(!s.empty()){              cur=s.top();              if( (NULL == cur->lchild&& NULL == cur->rchild)|| //该节点无左右子节点                   (pre!=NULL&&(cur->lchild== pre || cur->rchild == pre))){//该节点只有左或右子节点,且已经被访问                   cout<<cur->elem<<"";                   s.pop();                   pre=cur;              }else{//该节点无子节点,或未被访问                   if(NULL != cur->rchild )                       s.push(cur->rchild);                   if(NULL != cur->lchild)                       s.push(cur->lchild);              }         }     }}

 

完整代码实现:

#include<iostream>#include<stack>usingnamespace std; template<class T>classnode{public:     T elem;     struct node<T> *parent;     struct node<T> *lchild;     struct node<T> *rchild;}; template<class T>class bin_search_tree{public://  bin_search_tree(): root(NULL){}     bin_search_tree();     ~bin_search_tree(){}     void insert_elem(const T& elem);     bool remove_elem(const T& elem);     bool empty() const;      void pre_order() const;     void pre_order_recursive(node<T>* op_node)const;     void in_order() const;     void in_order_recursive(node<T>*op_node) const;     void post_order() const;     void post_order_recursive(node<T>*op_node) const;      node<T>* search_tree(const T&elem) const;     node<T>* get_root() const {returnroot;}     node<T>* minimum_elem(node<T>*root) const;     node<T>* maximum_elem(node<T>*root) const;     node<T>* precursor(const T& elem)const;     node<T>* successor(const T& elem)const;private:     node<T> *root;}; template<class T>bin_search_tree<T>::bin_search_tree(){     root = NULL;}template<class T>voidbin_search_tree<T>::insert_elem(const T& elem){     if(!empty()){         node<T> *new_node =  new node<T>;         new_node->elem = elem;         new_node->parent = NULL;         new_node->lchild = NULL;         new_node->rchild = NULL;          node<T> *temp_node = root;         node<T> *dest_parent_node = NULL;//待插入节点的父节点         while(temp_node){              dest_parent_node = temp_node;              if(temp_node->elem > elem)                   temp_node =temp_node->lchild;              else                   temp_node =temp_node->rchild;         }         if(dest_parent_node->elem > elem)              dest_parent_node->lchild=new_node;         else              dest_parent_node->rchild =new_node;         new_node->parent = dest_parent_node;      }else{ //空树,插入根节点         root = new node<T>;         root->elem = elem;         root->parent = NULL;         root->lchild = NULL;         root->rchild = NULL;     }} template<class T>node<T>*bin_search_tree<T>::search_tree(const T& elem) const{     node<T> * temp_node = root;     while(temp_node){         if(temp_node->elem == elem)              break;         else if(temp_node->elem > elem)              temp_node = temp_node->lchild;         else              temp_node = temp_node->rchild;     }     return temp_node;} template<class T>boolbin_search_tree<T>::remove_elem(const T& elem){     node<T> *rmv_node =search_tree(elem);     if(NULL != rmv_node){         node<T> *parent_node =rmv_node->parent;         if(NULL == rmv_node->lchild&& NULL == rmv_node->rchild){              if(NULL == rmv_node->parent){//只有根节点                   root = NULL;              }else{                   if(parent_node->lchild ==rmv_node)                       parent_node->lchild =NULL;                   else                       parent_node->rchild =NULL;              }              delete rmv_node;         }else if((NULL != rmv_node->lchild)&& (NULL == rmv_node->rchild)){//删除节点只有左子节点              if(NULL == rmv_node->parent){//只有根+一个左节点,删除根节点                   root = rmv_node->lchild;              }else if(parent_node->lchild ==rmv_node){                   parent_node->lchild =rmv_node->lchild;              }else{                   parent_node->rchild =rmv_node->lchild;              }              rmv_node->lchild->parent =parent_node;              delete rmv_node;         }else if((NULL != rmv_node->rchild)&& (NULL == rmv_node->lchild)){//删除节点只有右子节点                   if(NULL ==rmv_node->parent){//只有根+一个右节点,删除根节点                       root =rmv_node->rchild;                   }elseif(parent_node->lchild == rmv_node){                       parent_node->lchild =rmv_node->rchild;                   }else                       parent_node->rchild =rmv_node->rchild;                   rmv_node->rchild->parent= parent_node;                   delete rmv_node;         }else{//删除节点有左右子节点              node<T> *post =successor(rmv_node->elem); //post的左子树必然为空              if(post == rmv_node->rchild){                 rmv_node->rchild = post->rchild;                 if(NULL != post->rchild)                    post->rchild->parent= rmv_node;//                rmv_node->elem = post->elem;//                delete post;              }else{//                rmv_node->elem =post->elem;                   post->parent->lchild =NULL;//                delete post;              }              rmv_node->elem = post->elem;              delete post;         }         return true;     }     else //元素不存在         return false;} template<class T>void bin_search_tree<T>::pre_order_recursive(node<T>*op_node) const{     if(op_node != NULL){         cout<<op_node->elem<<"";         pre_order_recursive(op_node->lchild);         pre_order_recursive(op_node->rchild);     }} template<class T>voidbin_search_tree<T>::pre_order() const{     if(NULL != root){         stack< node<T>* > s;         node<T> *temp_node = NULL;         s.push(root);         while(!s.empty()){              temp_node = s.top();              cout<<temp_node->elem<<"";              s.pop();              if(NULL != temp_node->rchild)                   s.push(temp_node->rchild);              if(NULL != temp_node->lchild)                   s.push(temp_node->lchild);         }     }} template<class T>voidbin_search_tree<T>::in_order() const{     if(NULL != root){         node<T> *temp_node = NULL;         stack< node<T>* > s;         temp_node = root;         while((NULL != temp_node) || (!s.empty())){ //简洁版              if(NULL != temp_node){                   s.push(temp_node);                   temp_node =temp_node->lchild;              }              else{                   temp_node = s.top();                   s.pop();                   cout<<temp_node->elem<<"";                   temp_node =temp_node->rchild;              }         }/*       s.push(root);         while(!s.empty()){              temp_node = s.top();              while(NULL != temp_node){                   s.push(temp_node->lchild);                   temp_node =temp_node->lchild;              }              s.pop(); //pop empty node              if(!s.empty()){                   temp_node = s.top();                   cout<<temp_node->elem<<"";                   s.pop();                   s.push(temp_node->rchild);              }         }*/     }} template<class T>voidbin_search_tree<T>::in_order_recursive(node<T>* op_node) const{     if(op_node != NULL){         in_order_recursive(op_node->lchild);         cout<<op_node->elem<<"";         in_order_recursive(op_node->rchild);     }} template<class T>voidbin_search_tree<T>::post_order_recursive(node<T>* op_node) const{     if(op_node != NULL){         post_order_recursive(op_node->lchild);         post_order_recursive(op_node->rchild);         cout<<op_node->elem<<"";     }} template<class T>voidbin_search_tree<T>::post_order() const{     if(NULL != root){         stack<node<T>*> s;         node<T> *pre=NULL;//前一次访问节点,         node<T> *cur=NULL;//当前节点         s.push(root);         while(!s.empty()){              cur=s.top();              if( (NULL == cur->lchild&& NULL == cur->rchild)|| //该节点无左右子节点                   (pre!=NULL&&(cur->lchild== pre || cur->rchild == pre))){//该节点只有左或右子节点,且已经被访问                   cout<<cur->elem<<"";                   s.pop();                   pre=cur;              }else{//该节点无子节点,或未被访问                   if(NULL != cur->rchild )                       s.push(cur->rchild);                   if(NULL != cur->lchild)                       s.push(cur->lchild);              }         }     }} template<class T>boolbin_search_tree<T>::empty() const{     if(NULL == root)         return true;     else         return false;} template<class T>node<T>*bin_search_tree<T>::minimum_elem(node<T>* root) const{     node<T> *p_node=root;     while(p_node->lchild != NULL){         p_node = p_node->lchild;     }     return p_node;}template<class T>node<T>*bin_search_tree<T>::maximum_elem(node<T>* root) const{     node<T> *p_node=root;     while(p_node->rchild != NULL){         p_node = p_node->rchild;     }     return p_node;} template<class T>node<T>*bin_search_tree<T>::precursor(const T& elem) const{     node<T> *p_node = search_tree(elem);     if(NULL == p_node)         return NULL;     if(p_node->lchild)         returnmaximum_elem(p_node->lchild);//左子树最大的那个     else{//无左子树 ,如13,17        if(p_node == minimum_elem(root)){//是否为最小值,最小值无前驱            return NULL;         }          if(NULL == p_node->parent)              return NULL;         while(p_node!=NULL){//向上寻找前驱              if(p_node->parent->rchild ==p_node)                   break;              p_node = p_node->parent;         }         return p_node->parent;     }} template<class T>node<T>*bin_search_tree<T>::successor(const T& elem) const{     node<T> *p_node = search_tree(elem);     if(NULL == p_node)         return NULL;     if(p_node->rchild)         returnminimum_elem(p_node->rchild);//左子树最大的那个     else{//无右子树,查找某个结点的左子树遍历完了  eg. 13,17        if(p_node == maximum_elem(root)){//是否为最大值,最大值无后继            return NULL;         }         if(NULL == p_node->parent)              return NULL;         while(p_node){//向上寻找后继              if(p_node->parent->lchild ==p_node)                   break;              p_node = p_node->parent;         }         return p_node->parent;     }} intmain(){     bin_search_tree<int> bs_tree;     if(bs_tree.empty())         cout<<"the bin_search_treeis empty."<<endl;     else         cout<<"the bin_search_treeis not empty."<<endl;      node<int> *p_root=NULL;     node<int> *s_node=NULL;     bs_tree.insert_elem(15);     bs_tree.insert_elem(6);     bs_tree.insert_elem(18);     bs_tree.insert_elem(4);    bs_tree.insert_elem(17);     bs_tree.insert_elem(2);     bs_tree.insert_elem(20);     bs_tree.insert_elem(5);     bs_tree.insert_elem(13);     bs_tree.insert_elem(3);     bs_tree.insert_elem(7);     bs_tree.insert_elem(16);      p_root = bs_tree.get_root();     cout<<"pre order(recursive) :";     bs_tree.pre_order_recursive(p_root);cout<<endl;     cout<<"pre order : ";     bs_tree.pre_order();cout<<endl;     cout<<"in order(recursive) :";     bs_tree.in_order_recursive(p_root);cout<<endl;     cout<<"in order : ";     bs_tree.in_order();cout<<endl;     cout<<"post order(recursive) :";     bs_tree.post_order_recursive(p_root);cout<<endl;     cout<<"post order : ";     bs_tree.post_order();cout<<endl;      s_node = bs_tree.maximum_elem(p_root);     cout<<"maximum elem:"<<s_node->elem<<endl;     s_node = bs_tree.minimum_elem(p_root);     cout<<"minimum elem:"<<s_node->elem<<endl;      cout<<"---------------------------"<<endl;     s_node = bs_tree.precursor(2);     if(NULL!=s_node)         cout<<"2"<<"precursor: "<<s_node->elem<<endl;     else         cout<<"2 noprecursor."<<endl;     s_node = bs_tree.successor(2);     if(NULL!=s_node)         cout<<"2"<<"successor: "<<s_node->elem<<endl;     else         cout<<"2 nosuccessor."<<endl;      cout<<"---------------------------"<<endl;    s_node = bs_tree.precursor(13);     if(NULL!=s_node)         cout<<"13"<<"precursor: "<<s_node->elem<<endl;     else         cout<<"13 noprecursor."<<endl;     s_node = bs_tree.successor(6);     if(NULL!=s_node)         cout<<"6"<<"successor: "<<s_node->elem<<endl;     else         cout<<"6 nosuccessor."<<endl;      cout<<"---------------------------"<<endl;     s_node = bs_tree.precursor(20);     if(NULL!=s_node)         cout<<"20"<<"precursor: "<<s_node->elem<<endl;     else         cout<<"20 noprecursor."<<endl;     s_node = bs_tree.successor(20);     if(NULL!=s_node)         cout<<"20"<<"successor: "<<s_node->elem<<endl;     else         cout<<"20 nosuccessor."<<endl;     cout<<"---------------------------"<<endl;     bs_tree.remove_elem(15);     cout<<"pre order : ";     bs_tree.pre_order();cout<<endl;     cout<<"in order(recursive) :";     bs_tree.in_order_recursive(p_root);cout<<endl;     cout<<"post order : ";     bs_tree.post_order();cout<<endl;         cout<<"---------------------------"<<endl;     bs_tree.remove_elem(6);     cout<<"pre order : ";     bs_tree.pre_order();cout<<endl;     cout<<"in order(recursive) :";     bs_tree.in_order_recursive(p_root);cout<<endl;     cout<<"post order : ";     bs_tree.post_order();cout<<endl;     return 0;}

结果:


参考:

http://zh.wikipedia.org/wiki/%E4%BA%8C%E5%8F%89%E6%9F%A5%E6%89%BE%E6%A0%91

http://www.cnblogs.com/Anker/archive/2013/01/28/2880581.html

http://blog.csdn.net/touch_2011/article/details/6831924

http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

http://blog.csdn.net/touch_2011/article/details/6831924

0 0
原创粉丝点击