二叉搜索树
二叉搜索树算法:
1、直接输入搜索序列,构造出类似于折半搜索的判定树那样的树形结构,
就能很快实现搜索,这就是二叉搜索树。
2、二叉搜索树是一种动态的搜索结构,输入元素的关键码序列不同的话
会有不同形态的二叉搜索树。
3、二叉搜索树的定义:
二叉搜索树或者是一颗空树,或者是具有下列性质的二叉树。
a)每个结点都有一个作为搜索依据的关键码,所有结点的关键码各不相同
b)左子树上的所有结点的关键码都小于根结点的关键码。
c)右子树上的所有结点的关键码都大于根结点的关键码。
d)左子树和右子树也都是二叉搜索树。
由第四条可以推断出,二叉搜索树的定义也是递归的。
二叉搜索树常用来表示字典结构。
二叉搜索树的抽象类型定义:
#include<iostream> using namespace std; //二叉搜索树的结点表示 struct BinSearchNode { int key; //结点的关键码 BinSearchNode *lSearchTree; //左子树 BinSearchNode *rSearchTree; //右子树 BinSearchNode() { lSearchTree=NULL; rSearchTree=NULL; } }; //二叉搜索树的类定义 class BinSearchTree { public: //构造函数和析构函数 BinSearchTree() { bsnroot=NULL; } ~BinSearchTree() { } //二叉搜索树的关键算法,引用形参和非引用形参 void InsertSearchNode(BinSearchNode *&bsn, int data); //插入结点 void DeleteSearchNode(int key,BinSearchNode *&bsn); //删除结点 BinSearchNode * SearchBinaryTreeCurrent(int key,BinSearchNode *&bsn); //搜索当前结点 void MidTravel(BinSearchNode *bsn); //中序遍历输出 BinSearchNode *MinSearch(BinSearchNode *&bsn);//寻找中序下的第一个结点指针 BinSearchNode *ReturnSearchRoot() //返回二叉搜索树的根结点 { return bsnroot; } private: BinSearchNode *bsnroot; //二叉搜索树的根结点 };
二叉搜索树插入结点递归算法:
1、如果该结点为空,则该结点为空结点,则把这个值赋值给根结点。
2、如果不为空,则和父节点的键值比较,如果小于根结点,则递归建立左子树。
3、如果大于父结点,则递归建立右子树。
4、如果等于父结点,则报错。
void BinSearchTree::InsertSearchNode(BinSearchNode *&bsn, int data) { if(bsn==NULL) { //错误一:忘记了新建结点,分配存储空间 bsn=new BinSearchNode; //新建结点 if(bsn==NULL)cout<<"新建新结点出错"<<endl; else { bsn->key=data; } } else { if(data<bsn->key) //bsn { InsertSearchNode(bsn->lSearchTree,data); } else if(data>bsn->key) { InsertSearchNode(bsn->rSearchTree,data); } else { cout<<"非法结点"<<endl; } } }
中序遍历输出递归算法:
void BinSearchTree::MidTravel(BinSearchNode *bsn) { //if(bsn==NULL) //这样写是错的,因为每次指针为空的时候都会打印这句话 //{ //cout<<"这是一颗空的二叉搜索树"<<endl; //} if(bsn!=NULL) { MidTravel(bsn->lSearchTree); cout<<bsn->key<<" "; //找到第一个结点指针 MidTravel(bsn->rSearchTree); } }
二叉搜索树的搜索算法:
1、从根结点开始,如果根结点为空,则返回空
2、如果小于根结点的值,则递归搜索左子树
3、如果大于根结点的值,则递归搜索右子树
4、否则找到了该结点,返回真
BinSearchNode* BinSearchTree::SearchBinaryTreeCurrent(int key,BinSearchNode *&bsn) { if(bsn==NULL) return false; else if(bsn->key>key) { SearchBinaryTreeCurrent(key,bsn->lSearchTree); } else if(bsn->key<key) { SearchBinaryTreeCurrent(key,bsn->rSearchTree); } else return bsn; }
二叉搜索树的删除结点算法:
删除算法中需要将因删除结点而断开的二叉链表重新连接起来,同时确保二叉树
性质不会失去,还要防止重新链接后的树的高度不会增加。
规则:右子树为空,左子女填补;左子树为空,右子女填补;左子树和右子树
都不为空,则寻找中序下的第一个结点,关键码最小的结点。如果是第二小,
则右子树中有小于根结点的结点,失去了二叉搜索树的性质。
1、搜索定位到该键值对应的指针处。
2、判断该该指针的右子树为空,则将该结点赋值给一个临时指针,然后将左子树覆盖这个指针,删除临时指针。
3、如果左子树为空,则用右子女代替。
4、如果左子树和右子树都不为,则搜索该结点的右子树中搜索中序下的第一个结点,
赋值给该结点,再处理该中序结点的删除问题。:以删除的结点值的键值为键值,在当前结点的右子树中递归搜索删除该结点。
5、如果左右子树都为空,则直接删除。
void BinSearchTree::DeleteSearchNode(int key,BinSearchNode *&bsn) { //错误:current这个本地指针不是引用型形参,修改它的的情况未知,诀窍,只有引用型形参才能这样用 if(key>bsn->key)DeleteSearchNode(key,bsn->rSearchTree); else if(key<bsn->key)DeleteSearchNode(key,bsn->lSearchTree); else { BinSearchNode *p=NULL; if(bsn->lSearchTree!=NULL&&bsn->rSearchTree!=NULL) { //下列写法不对 //要删除结点有两个子树 /*p=bsn; //1、找到最小的键值 //bsn=bsn->rSearchTree; 这样写难道有错? bsn=bsn->rSearchTree; while(bsn->lSearchTree!=NULL)bsn=bsn->lSearchTree; p->key=bsn->key; //2、递归删除 DeleteSearchNode(bsn->key,bsn);*/ p=bsn->rSearchTree; //在右子树中寻找中序下的第一个结点 while(p->lSearchTree!=NULL) p=p->lSearchTree; //第一个左子树 bsn->key=p->key; //用该结点值取代根结点数据 DeleteSearchNode(bsn->key,bsn->rSearchTree); //:以删除的结点值的键值为键值,在当前结点的右子树中递归搜索删除该结点。 } else { //引用型指针参数自动带动相关结点的修改 p=bsn; //被删除结点有一个子树 if(bsn->lSearchTree==NULL) bsn=bsn->rSearchTree; else bsn=bsn->lSearchTree; delete p; } } } /* 寻找中序下的第一个结点指针: */ BinSearchNode* BinSearchTree::MinSearch(BinSearchNode *&bsn) { if(bsn!=NULL) { MinSearch(bsn->lSearchTree); return bsn; MinSearch(bsn->rSearchTree); } }
二叉搜素树是一种重要的搜索结果,下一节将构造一颗更优的二叉搜索树。