数据结构:二叉搜索树
来源:互联网 发布:js将list转换为数组 编辑:程序博客网 时间:2024/05/18 21:42
资料摘自<数据结构C++语言描述>
一棵普通的二叉树中可以存放数据,且在我们需要增加、删除或查找数据项时能提供快速访问。树结构可以显著地发送搜索的性能,因为到达一个数据的路径最长不超过树的深度。
对于一个含10000个元素的表,用顺序搜索法查找一个元素的预期比较次数是5000,而在一棵完全二叉树上进行同样的搜索,需要进行的比较不会超过14次。
为了将元素存储在树中以供有效访问,必须设计一种可以标识到达元素的路径的搜索结构。这种结构被称作二叉搜索树,它用关系运算符”<”对元素进行排序。为了比较树中的结点,我们可以将数据域的整体或部分指定为键值,每当树中添加一项,“<”运算符都要将其与键值比较。二叉搜索树由下列规则构成:
对于每个节点,其左子树中的数据值都小于节点本身的值,而右子树中的数据值都大于或等于节点值。
下面图11.14是一个二叉搜索树的一个例子:
搜索37,由根开始需要4次比较:
当前节点 动作
根=50 比较键值37和50,因为37<50,故扫描左子树
节点=30 比较键值37和30,因为37>30,故扫描右子树
节点=35 比较键值37和35,因为37>35,故扫描右子树
节点=37 比较键值37和37,找到数据项
下面是二叉搜索树的部分定义与实现:
template<class T>
class BinSTree
{
protected:
TreeNode<T> * root;
TreeNode<T> * current;
int size;
TreeNode<T> * getTreeNode(const T & item, TreeNode<T> *lptr, TreeNode<T> * rptr); //
void freeTreeNode(TreeNode<T> * p); //
TreeNode<T> * copyTree(TreeNode<T> * t); //
void deleteTree(TreeNode<T> * t); //
TreeNode<T> * findNode(const T & item, TreeNode<T> * & parent) const; //
public:
BinSTree();
BinSTree(const BinSTree<T> & tree);
~BinSTree();
BinSTree<T> & operator = (const BinSTree<T> & rhs); //
bool find(T & item); //
void insert(const T & item); //
void Delete(const T & item); //
void clearTree(); // ==
bool listEmpty() const; //
int listSize() const; //
void update(const T & item); //
TreeNode<T> * getRoot() const; //
};
template<class T>
TreeNode<T> * BinSTree<T>::getTreeNode(const T& item, TreeNode<T> *lptr, TreeNode<T> *rptr){
TreeNode<T> * p;
p = new TreeNode<T>(item,lptr,rptr);
if(p == NULL){
std::cerr<<"memory allocation failure ! "<<std::endl;
exit(1);
}
return p;
}
template<class T>
void BinSTree<T>::freeTreeNode(TreeNode<T> * p){
delete p;
}
template<class T>
TreeNode<T> * BinSTree<T>::copyTree(TreeNode<T> * t){
TreeNode<T> *newlptr, *newrptr, *newnode;
if(t == NULL){
return NULL;
}
if(t->Left() != NULL){
newlptr = copyTree(t->Left());
}else{
newlptr = NULL;
}
if(t->Right() != NULL){
newrptr = copyTree(t->Left());
}else{
newrptr = NULL;
}
newnode = getTreeNode(t->data, newlptr, newrptr);
return newnode;
}
template<class T>
void BinSTree<T>::deleteTree(TreeNode<T> * t){
if(t != NULL){
deleteTree(t->Left());
deleteTree(t->Right());
freeTreeNode(t);
}
}
template<class T>
int BinSTree<T>::listSize() const{
return this->size;
}
template<class T>
bool BinSTree<T>::listEmpty() const {
return this->size == 0;
}
template<class T>
TreeNode<T> * BinSTree<T>::getRoot() const{
return this->root;
}
template<class T>
BinSTree<T> & BinSTree<T>::operator=(const BinSTree<T> & rhs){
if(this == rhs){
return *this;
}
this->clearList();
this->root = this->copyTree(rhs.root);
this->current = this->root;
this->size = rhs.size;
return * this;
}
template<class T>
TreeNode<T> * BinSTree<T>::findNode(const T & item, TreeNode<T> * & parent) const {
TreeNode<T> * t = this->root;
parent = NULL;
while(t !== NULL){
if(item == t->data){
break;
}else{
parent = t;
if(item < t->data){
t = t->Left();
}else{
t = t->Right();
}
}
}
return t;
}
template<class T>
bool BinSTree<T>::find(T & item) {
TreeNode<T> * parent;
this->current = this->findNode(item, parent);
if(this->current != NULL){
//item = this->current->data;
return true;
}else{
return false;
}
}
//insert方法以新数据项为参数对树进行搜索以找到合适的位置将其添加
//到树中。函数反复扫描左右子树中的路径直到找到插入点的位置。对于
//对于路径中的每一步,算法才都记录下当前节点(称作t)以及当前节点的
//双亲(称作parent)。整个过程在我们识别出空子树(t=NULL)后终止,它
//表示我们已经找到插入新数据项的位置。此时将新节点作为双亲的子节
//点插入到该位置。
template<class T>
void BinSTree<T>::insert(const T & item){
TreeNode<T> * t = this->root, * parent = NULL, *newNode;
while(t != NULL){
parent = t;
if(item < t->data){
t = t->Left();
}else{
t = t->Right();
}
}
newNode = this->getTreeNode(item,NULL,NULL);
if(parent == NULL){
this->root = newNode;
}else if(item < parent->data){
parent->left = newNode;
}else{
parent->right = newNode;
}
++this->size;
}
//若item在树中,将其删除
template<class T>
void BinSTree<T>::Delete(const T & item){
//DNodePtr 指向被删除节点D
//PNodePtr 指向节点D的双亲节点
//RNodePtr 指向替换D节点
TreeNode<T> * DNodePtr, * PNodePtr, * RNodePtr;
//搜索数据值为item的节点,并保存该节点的双亲节点指针
if((DNodePtr = this->findNode(item,PNodePtr)) == NULL) {
return;
}
//若D有一个指针为NULL,则替换节点为其另一枝的某一节点
if(DNodePtr->Right() == NULL){
RNodePtr = DNodePtr->Left();
}else if(DNodePtr->Left() == NULL){
RNodePtr = DNodePtr->Right();
}else{
//DNodePtr的两个子节点均不为NULL
//寻找并卸下D的替换节点。
//从节点D的左子树开始,找数据值小于D的数据值的
//最大值,将该节点从树中断开
//PofRNodePtr 指向替换节点双亲的指针
TreeNode<T> * PofRNode = DNodePtr;
//第一种可能的替换为D的左节点
RNodePtr = DNodePtr->left;
//从D的左节点的右子树继续往下搜索最大值,并记录当前节点及其双亲节点
//指针,最后我们找到替换节点
while(RNodePtr->right != NULL){
PofRNode = RNodePtr;
RNodePtr = RNodePtr->right;
}
if(PofRNode == DNodePtr){
//被删除节点的左节点为替换节点,将D的右子树赋给R
RNodePtr->right = DNodePtr->right;
}else{
//至少往右子树移动了一个节点,从树中删除替换节点,将其左子树赋给其双亲
PofRNode->right = RNodePtr->left;
//用替换节点代替DNodePtr
RNodePtr->left = DNodePtr->left;
RNodePtr->right = DNodePtr->right;
}
}
//完成到双亲节点的连结
if(PNodePtr == NULL){
this->root = RNodePtr;
}else if(DNodePtr->data < PNodePtr->data){
//要删除的节点位于左子树上
PNodePtr->left = RNodePtr;
}else{
PNodePtr->right = RNodePtr;
}
this->freeTreeNode(DNodePtr);
--this->size;
}
//更新节点数据
template<class T>
void BinSTree<T>::update(const T & item){
if(this->current != NULL && this->current->data == item){
this->current->data = item;
}else{
insert(item);
}
}
- 数据结构二叉搜索树
- 数据结构-----二叉搜索树
- 数据结构:二叉搜索树
- 数据结构 ---- 二叉搜索树
- 数据结构-二叉搜索树
- 【数据结构】二叉搜索树
- 【数据结构】二叉搜索树
- 数据结构---------二叉搜索树
- 数据结构--‘搜索二叉树’
- 【数据结构】二叉搜索树
- 【数据结构】二叉搜索树
- 数据结构::搜索二叉树
- 【数据结构】二叉搜索树
- 数据结构-二叉搜索树
- 数据结构:二叉搜索树
- 数据结构 二叉搜索树
- 数据结构--二叉搜索树
- 数据结构 二叉搜索树
- 动态规划 编辑距离
- CSU 1611: Concatenation(状态压缩DP)
- hud1326 排序水题
- php中empty()和isset()函数的区别
- day12/WaitNotifyThread.java
- 数据结构:二叉搜索树
- 链表 Remove Duplicates from Sorted List II
- HDU 4586 Play the Dice(规律+推导)
- day13/Jibenshujuleixing.java
- 双向循环链表 函数的实现
- JavaScript扩展String的方法
- zoj-2563(1×3铺地砖)
- day13/MyIndexOfString.java
- LintCode 两个字符串是变位词