二叉查找树的概念以及实现 前序、中序和后序递归非递归遍历算法
来源:互联网 发布:机械生命体网络 编辑:程序博客网 时间:2024/05/17 23:28
本文主要介绍二叉查找树以及实现,另外实现前序、中序和后序递归非递归遍历算法。
二叉查找树:
概述:
《算法导论》第12章介绍了二叉查找树的主要性质。
二叉查找树(Binary Search Tree),也称二叉搜索树、有序二叉树(orderedbinary tree),排序二叉树(sorted binary tree),具有以下性质:
- 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 任意节点的左、右子树也分别为二叉查找树。
- 没有键值相等的节点(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、 有左右节点:找到该节点的后继(后继的左节点必然为空,如15,6,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
- 二叉查找树的概念以及实现 前序、中序和后序递归非递归遍历算法
- 【二叉树遍历算法】——前/中/后序递归与非递归的实现
- 二叉树的前序,中序,后序遍历。用递归和非递归实现
- 二叉树的遍历(前序,中序,后序,层序)--递归和非递归算法实现
- 二叉树的前序遍历、中序遍历和后序遍历的递归和非递归算法
- 用java实现二叉树非递归的前序,中序,后序遍历算法
- 【二叉树】 前序、中序和后序的递归遍历与非递归遍历
- 二叉树非递归前、中、后序遍历实现
- 【二叉树】非递归遍历的通用算法:前序、中序和后序
- 扩展二叉树 建立 以及 前序遍历 中序遍历 后序遍历 的非递归算法
- 二叉树的遍历(前 中 后序 )递归 非递归算法
- (前、中、后)序遍历二叉树的递归、非递归算法!
- 【数据结构】二叉树(前、中、后)序遍历的递归与非递归算法
- 二叉树的遍历 前序 中序 后序 分别实现递归和非递归遍历方式
- 二叉树的前序、中序、后序的递归与非递归遍历算法实现
- 二叉树的前序、中序、后序的递归与非递归遍历算法实现(待完善)
- 二叉树的前序、中序、后序遍历 递归非递归实现
- 二叉树的前序、中序、后序(递归、非递归)遍历java实现
- (转载)android设备导入sqlite3文件
- fdhkkfyilyi
- 查询mysql表字段信息的sql语句
- 将对象转为Map
- 浅谈oracle中row_number() over()分析函数用法
- 二叉查找树的概念以及实现 前序、中序和后序递归非递归遍历算法
- hadoop的编程实例
- 怎样让多个版本的JDK在系统环境中被不同依赖软件识别
- Socket通信中的多进程编程实例
- 关于NSCalendar 日历的学习记录
- 驱动笔记
- Oracle 10G R2 全版本快速下载地址
- UVA10815
- EBS提供的所有Key Flexfields(KFF)