《算法导论》读书笔记之第12章 二叉查找树
2013-01-28 21:49
316 查看
摘要:
本章介绍了二叉查找树的概念及操作。主要内容包括二叉查找树的性质,如何在二叉查找树中查找最大值、最小值和给定的值,如何找出某一个元素的前驱和后继,如何在二叉查找树中进行插入和删除操作。在二叉查找树上执行这些基本操作的时间与树的高度成正比,一棵随机构造的二叉查找树的期望高度为O(lgn),从而基本动态集合的操作平均时间为θ(lgn)。
1、二叉查找树
二叉查找树是按照二叉树结构来组织的,因此可以用二叉链表结构表示。二叉查找树中的关键字的存储方式满足的特征是:设x为二叉查找树中的一个结点。如果y是x的左子树中的一个结点,则key[y]≤key[x]。如果y是x的右子树中的一个结点,则key[x]≤key[y]。根据二叉查找树的特征可知,采用中根遍历一棵二叉查找树,可以得到树中关键字有小到大的序列。/article/4834198.html介绍了二叉树概念及其遍历。一棵二叉树查找及其中根遍历结果如下图所示:
View Code
程序测试结果如下所示:
二叉树实现时候添加了一个父结点指针,方便寻找给定结点的前驱和后继。二叉树中删除操作实现比较复杂,需要分类讨论,我分三种情况进行讨论,程序写的有些繁琐,可以进行优化。优化后的代码如下:
5、随机构造二叉查找树
二叉查找上各种基本操作的运行时间都是O(h),h为树的高度。但是在元素插入和删除过程中,树的高度会发生改变。如果n个元素按照严格增长的顺序插入,那个构造出的二叉查找树的高度为n-1。例如按照先后顺序插入7、15、18、20、34、46、59元素构造二叉查找树,二叉查找树结构如下所示:
本章介绍了二叉查找树的概念及操作。主要内容包括二叉查找树的性质,如何在二叉查找树中查找最大值、最小值和给定的值,如何找出某一个元素的前驱和后继,如何在二叉查找树中进行插入和删除操作。在二叉查找树上执行这些基本操作的时间与树的高度成正比,一棵随机构造的二叉查找树的期望高度为O(lgn),从而基本动态集合的操作平均时间为θ(lgn)。
1、二叉查找树
二叉查找树是按照二叉树结构来组织的,因此可以用二叉链表结构表示。二叉查找树中的关键字的存储方式满足的特征是:设x为二叉查找树中的一个结点。如果y是x的左子树中的一个结点,则key[y]≤key[x]。如果y是x的右子树中的一个结点,则key[x]≤key[y]。根据二叉查找树的特征可知,采用中根遍历一棵二叉查找树,可以得到树中关键字有小到大的序列。/article/4834198.html介绍了二叉树概念及其遍历。一棵二叉树查找及其中根遍历结果如下图所示:
View Code
#include <iostream> #include <stack> #include <cstdlib> using namespace std; template <class T> class BinarySearchTreeNode { public: T elem; struct BinarySearchTreeNode<T> *parent; struct BinarySearchTreeNode<T>* left; struct BinarySearchTreeNode<T>* right; }; template <class T> class BinarySearchTree { public: BinarySearchTree(); void tree_insert(const T& elem); int tree_remove(const T& elem ); BinarySearchTreeNode<T>* tree_search(const T& elem)const; T tree_minmum(BinarySearchTreeNode<T>* root)const; T tree_maxmum(BinarySearchTreeNode<T>* root)const; T tree_successor(const T& elem) const; T tree_predecessor(const T& elem)const; int empty() const; void inorder_tree_walk()const; BinarySearchTreeNode<T>* get_root()const {return root;} private: BinarySearchTreeNode<T>* root; }; template <class T> BinarySearchTree<T>::BinarySearchTree() { root = NULL; } template <class T> void BinarySearchTree<T>::tree_insert(const T& elem) { if(!empty()) { BinarySearchTreeNode<T> *pnode = root; BinarySearchTreeNode<T> *qnode = NULL; BinarySearchTreeNode<T> *newnode = new BinarySearchTreeNode<T>; newnode->elem = elem; newnode->parent = NULL; newnode->left = NULL; newnode->right = NULL; while(pnode) { qnode = pnode; if(pnode->elem > elem) pnode = pnode->left; else pnode = pnode->right; } if(qnode->elem > elem) qnode->left = newnode; else qnode->right = newnode; newnode->parent = qnode; } else { root = new BinarySearchTreeNode<T>; root->elem = elem; root->parent =NULL; root->left = NULL; root->right = NULL; } } template <class T> int BinarySearchTree<T>::tree_remove(const T&elem) { BinarySearchTreeNode<T> *pnode; BinarySearchTreeNode<T> *parentnode,*snode; pnode = tree_search(elem); if(pnode != NULL) { parentnode = pnode->parent; if(pnode->right == NULL || pnode->left == NULL) { if(pnode->right != NULL) { if(parentnode->left == pnode) parentnode->left = pnode->right; if(parentnode->right == pnode) parentnode->right = pnode->right; pnode->right->parent = parentnode; } else if(pnode->left != NULL) { if(parentnode->left == pnode) parentnode->left = pnode->left; if(parentnode->right == pnode) parentnode->right = pnode->left; pnode->left->parent = parentnode; } else { if(parentnode->left == pnode) parentnode->left = NULL; if(parentnode->right == pnode) parentnode->right = NULL; } delete pnode; } else { snode = tree_search(tree_successor(pnode->elem)); pnode->elem = snode->elem; if(snode->parent->left == snode) { snode->parent->left = snode->right; snode->right->parent = snode->parent->left; } if(snode->parent->right == snode) { snode->parent->right = snode->right; snode->right->parent = snode->parent->right; } delete snode; } return 0; } return -1; } template <class T> BinarySearchTreeNode<T>* BinarySearchTree<T>::tree_search(const T& elem)const { BinarySearchTreeNode<T> *pnode = root; while(pnode) { if(pnode->elem == elem) break; else if(pnode->elem > elem) pnode = pnode->left; else pnode = pnode->right; } return pnode; } template <class T> T BinarySearchTree<T>::tree_minmum(BinarySearchTreeNode<T>* root)const { BinarySearchTreeNode<T> *pnode = root; if(pnode->left) { while(pnode->left) pnode = pnode->left; } return pnode->elem; } template <class T> T BinarySearchTree<T>::tree_maxmum(BinarySearchTreeNode<T>* root)const { BinarySearchTreeNode<T> *pnode = root; if(pnode->right) { while(pnode->right) pnode = pnode->right; } return pnode->elem; } template <class T> T BinarySearchTree<T>::tree_successor(const T& elem) const { BinarySearchTreeNode<T>* pnode = tree_search(elem); BinarySearchTreeNode<T>* parentnode; if(pnode != NULL) { if(pnode->right) return tree_minmum(pnode->right); parentnode = pnode->parent; while(parentnode && pnode == parentnode->right) { pnode = parentnode; parentnode = parentnode->parent; } if(parentnode) return parentnode->elem; else return T(); } return T(); } template <class T> T BinarySearchTree<T>::tree_predecessor(const T& elem)const { BinarySearchTreeNode<T>* pnode = tree_search(elem); BinarySearchTreeNode<T>* parentnode; if(pnode != NULL) { if(pnode->right) return tree_maxmum(pnode->right); parentnode = pnode->parent; while(parentnode && pnode == parentnode->left) { pnode = parentnode; parentnode = pnode->parent; } if(parentnode) return parentnode->elem; else return T(); } return T(); } template <class T> int BinarySearchTree<T>::empty() const { return (NULL == root); } template <class T> void BinarySearchTree<T>::inorder_tree_walk()const { if(NULL != root) { stack<BinarySearchTreeNode<T>*> s; BinarySearchTreeNode<T> *ptmpnode; ptmpnode = root; while(NULL != ptmpnode || !s.empty()) { if(NULL != ptmpnode) { s.push(ptmpnode); ptmpnode = ptmpnode->left; } else { ptmpnode = s.top(); s.pop(); cout<<ptmpnode->elem<<" "; ptmpnode = ptmpnode->right; } } } } int main() { BinarySearchTree<int> bstree; BinarySearchTreeNode<int>* ptnode,*proot; bstree.tree_insert(32); bstree.tree_insert(21); bstree.tree_insert(46); bstree.tree_insert(54); bstree.tree_insert(16); bstree.tree_insert(38); bstree.tree_insert(70); cout<<"inorder tree walk is: "; bstree.inorder_tree_walk(); proot = bstree.get_root(); cout<<"\nmax value is: "<<bstree.tree_maxmum(proot)<<endl; cout<<"min value is: "<<bstree.tree_minmum(proot)<<endl; ptnode = bstree.tree_search(38); if(ptnode) cout<<"the element 38 is exist in the binary tree.\n"; else cout<<"the element 38 is not exist in the binary tree.\n"; cout<<"the successor of 38 is: "<<bstree.tree_successor(38)<<endl; cout<<"the predecessor of 38 is:"<<bstree.tree_predecessor(38)<<endl; if(bstree.tree_remove(46) == 0) cout<<"delete 46 successfully"<<endl; else cout<<"delete 46 failed"<<endl; cout<<"inorder tree walk is: "; bstree.inorder_tree_walk(); exit(0); }
程序测试结果如下所示:
二叉树实现时候添加了一个父结点指针,方便寻找给定结点的前驱和后继。二叉树中删除操作实现比较复杂,需要分类讨论,我分三种情况进行讨论,程序写的有些繁琐,可以进行优化。优化后的代码如下:
template <class T> int BinarySearchTree<T>::tree_delete(const T& elem) { //找到该元素对应的结点 BinarySearchTreeNode<T>* pnode = tree_search(elem); if(NULL != pnode) { BinarySearchTreeNode<T> *qnode,*tnode; //判断结点是否有左右孩子 if(pnode->left == NULL || pnode->right == NULL) qnode = pnode; //有一个左孩子或者一个右孩子和没有左右孩子 else qnode = tree_search(tree_successor(elem)); //有左右孩子 if(NULL != qnode->left) tnode = qnode->left; else tnode = qnode->right; if(NULL != tnode) tnode->parent = qnode->parent; if(qnode->parent == NULL) root = tnode; else if(qnode == qnode->parent->left) qnode->parent->left = tnode; else qnode->parent->right = tnode; if(qnode != pnode) pnode->elem = qnode->elem; //将后继结点的值复制到要删除的结点的值 delete qnode; return 0; } return -1; }
5、随机构造二叉查找树
二叉查找上各种基本操作的运行时间都是O(h),h为树的高度。但是在元素插入和删除过程中,树的高度会发生改变。如果n个元素按照严格增长的顺序插入,那个构造出的二叉查找树的高度为n-1。例如按照先后顺序插入7、15、18、20、34、46、59元素构造二叉查找树,二叉查找树结构如下所示:
相关文章推荐
- 《算法导论》读书笔记之第12章 二叉查找树
- 《算法导论》读书笔记之第12章 二叉查找树
- 《算法导论》读书笔记之第12章 二叉查找树
- 《算法导论》笔记 第12章 12.2 查询二叉查找树
- 算法导论 第12章 二叉查找树
- 《算法导论》第12章 二叉查找树 (2)查找、插入与删除
- 算法导论 第12章 二叉查找树
- 《算法导论》笔记 第12章 12.2 查询二叉查找树
- 《算法导论》第12章 二叉查找树 (2)查找、插入与删除
- 《算法导论》第12章 二叉查找树 (3)基数树
- 《算法导论》第12章 二叉查找树 (3)基数树(转)
- 《算法导论》第12章 二叉查找树 (3)基数树
- 《算法导论》读书笔记之第15章 动态规划—最优二叉查找树
- 《算法导论》第12章 二叉查找树 (3)基数树
- 算法导论第12章 二叉查找树中的后继
- 《算法导论》第12章 二叉查找树 (1)遍历
- 《算法导论》第12章 二叉查找树 (3)基数树
- 《算法导论》学习总结 — 11. 第12章 二叉查找树
- 《算法导论》第12章 二叉查找树 (1)遍历
- 算法导论--第12章【二叉查找树】