二叉排序树
有关二叉排序树的概念与操作,移步Hear。
平衡二叉树概念
- 特殊类型的二叉排序树。二叉排序树的查找性能取决于二叉树的结构。树的高度越小,查找速度越快。
注意:如果连二叉排序树都不是,那肯定不是平衡二叉树。 - 如果非空,左子树与右子树深度之差的绝对值不超过1.
- 左子树与右子树也是平衡二叉树。
结点定义
它基本和二叉排序树差不多,就是多了个记录结点高度(用来计算平衡因子)的字段。
typedef int KeyType;
typedef int OtherInfo;
//----------二叉排序树存储表示-----------
typedef struct{
KeyType key; //关键字项
OtherInfo info; //其他数据信息
}ElemType;
typedef struct BSTNode {
ElemType data; //每个结点的数据域包括关键字项和其他信息
struct BSTNode *lchild;
struct BSTNode *rchild;
int nHeight; /*树的高度,可以计算平衡因子*/
} BSTNode,*BSTree;
平衡二叉树的操作
平衡二叉树的平衡调整方法
-
LL型
指插入以A为根的左子树的左子树上破坏了平衡。
插入7或10之后53的平衡因子变为2,高了,怎么降低?那就是把高的转下来(顺时针)。主要就是 根和图中三角形那 发生了变化。三角形那可以为空。static BSTree SingleRotateWithLeft(BSTree pNode) //LL型 { BSTNode *pNode1; pNode1 = pNode->lchild; //图中9 pNode->lchild = pNode1->rchild; pNode1->rchild = pNode; /*结点的位置变了, 要更新结点的高度值*/ pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1; pNode1->nHeight = Max(Height(pNode1->lchild), pNode->nHeight) + 1; return pNode1; }
指插入以A为根的右子树的右子树上破坏了平衡。
插入58或70之后17的平衡因子变为-2,高了,怎么降低?那就是把高的转下来(逆时针)。主要就是 根和图中三角形那 发生了变化。三角形那可以为空。static BSTree SingleRotateWithRight(BSTree pNode) //RR型 { BSTNode *pNode1; pNode1 = pNode->rchild; //图中53 pNode->rchild = pNode1->lchild; pNode1->lchild = pNode; /*结点的位置变了, 要更新结点的高度值*/ pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1; pNode1->nHeight = Max(Height(pNode1->rchild), pNode->nHeight) + 1; return pNode1; }
指插入以A为根的左子树的右子树上破坏了平衡。
插入25或35之后53的平衡因子为2,需要旋转,一步不能解决,那就转两次。
先把53的左子树进行RR型旋转,得到中间图,再把中间图进行LL型旋转即可。static BSTree DoubleRotateWithLeft(BSTree pNode) //LR型 { pNode->lchild = SingleRotateWithRight(pNode->lchild); return SingleRotateWithLeft(pNode); }
指插入以A为根的右子树的左子树中破坏了平衡。
插入55或59之后53的平衡因子为-2,需要旋转,一步不能解决,那就转两次。
先把53的右子树进行LL型旋转,得到中间图,再把中间图进行RR型旋转即可。static BSTree DoubleRotateWithRight(BSTree pNode) { pNode->rchild = SingleRotateWithLeft(pNode->rchild); //RL型 return SingleRotateWithRight(pNode); }
总的代码:
#include <iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;
#define Max(a,b) ((a)>(b)?(a):(b))
typedef int KeyType;
typedef int OtherInfo;
//----------二叉排序树存储表示-----------
typedef struct{
KeyType key; //关键字项
OtherInfo info; //其他数据信息
}ElemType;
typedef struct BSTNode {
ElemType data; //每个结点的数据域包括关键字项和其他信息
struct BSTNode *lchild;
struct BSTNode *rchild;
int nHeight; /*树的高度,可以计算平衡因子*/
} BSTNode,*BSTree;
void InsertBST(BSTree &T,ElemType e); /*插入操作*/
BSTree SearchBST(BSTree T,KeyType key); /*查找操作*/
bool delete_BSTree(BSTree &T,int key); /*删除操作*/
/*打印操作*/
void PreOrder(BSTree T); //递归先序遍历
void InOrder(BSTree T); //递归中序遍历
static int Height(BSTree pNode);
/*旋转操作*/
static BSTree SingleRotateWithLeft(BSTree pNode);
static BSTree SingleRotateWithRight(BSTree pNode);
static BSTree DoubleRotateWithLeft(BSTree pNode);
static BSTree DoubleRotateWithRight(BSTree pNode);
void PreOrder(BSTree T){//递归先序遍历
if(T!=NULL){
cout<<T->data.key<<" ";
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
void InOrder(BSTree T){//递归中序遍历
if(T!=NULL){
InOrder(T->lchild);
cout<<T->data.key<<" ";
InOrder(T->rchild);
}
}
BSTree SearchBST(BSTree T,KeyType key) {
if ((!T) || key == T->data.key)
return T;
else if (key < T->data.key)
return SearchBST(T->lchild, key);
else return SearchBST(T->rchild, key);
}
/*得到节点的高度以计算平衡因子*/
static int Height(BSTree pNode)
{
if (NULL == pNode)
return 0;
return pNode->nHeight;
}
void InsertBST(BSTree &T,ElemType e)
{
if(!T){ //找到插入位置
BSTree S=new BSTNode; //新节点保存数据
S->data=e;
S->nHeight = 0;
S->lchild=S->rchild=NULL;
T=S; //把新结点放到已找到的插入位置
}
else if(e.key < T->data.key){
InsertBST(T->lchild,e);
if (Height(T->lchild) - Height(T->rchild) == 2) /*AVL树不平衡*/
{
cout<<"因为"<<T->data.key<<"左孩子高度"<<Height(T->lchild);
cout<<"大于右孩子高度"<<Height(T->rchild)<<endl;
if (e.key < T->lchild->data.key)
{ /*插入到了左子树左边, 做单旋转*/
cout<<"发生LL型旋转"<<endl;
T = SingleRotateWithLeft(T);
}
else
{ /*插入到了左子树右边, 做双旋转*/
cout<<"发生LR型旋转"<<endl;
T = DoubleRotateWithLeft(T);
}
}
}
else if(e.key > T->data.key) {
InsertBST(T->rchild,e);
if (Height(T->rchild) - Height(T->lchild) == 2) /*AVL树不平衡*/
{
cout<<"因为"<<T->data.key<<"左孩子高度"<<Height(T->lchild);
cout<<"小于右孩子高度"<<Height(T->rchild)<<endl;
if (e.key > T->rchild->data.key)
{ /*插入到了右子树右边, 做单旋转*/
cout<<"发生RL旋转"<<endl;
T = SingleRotateWithRight(T);
}
else
{ /*插入到了右子树左边, 做双旋转*/
cout<<"发生RR旋转"<<endl;
T = DoubleRotateWithRight(T);
}
}
}
else{
cout<<"已有此值~"<<endl;
return;
}
T->nHeight = Max(Height(T->lchild), Height(T->rchild)) + 1;
}
void delete_Node1(BSTree &p)
{
BSTree q,s;
if(!p->lchild) //由于这个if在前面,所以左右子树均为空的情况会在这里处理
{ //如果左子树为空,则只需重接其右子树
q = p;
p = p->rchild ;
free(q);
}
else if(!p->rchild)
{ //如果右子树为空,则只需重接其左子树
q = p;
p = p->lchild;
free(q);
}
else
{ //如果左右子树都不为空,这里采取修改左子树的方法,也可以修改右子树,方法类似
s = p->lchild; //取待删节点的左孩子结点
while(s->rchild) //找到中序遍历时会得到的直接前驱
s = s->rchild;
s->rchild = p->rchild; //将p的右子树接为s的右子树
q = p;
p = p->lchild; //将p的左子树直接接到其父节点的左子树上
free(q);
}
}
void delete_Node2(BSTree &p)
{
BSTree q,s;
if(!p->lchild) //由于这个if在前面,所以左右子树均为空的情况会在这里处理
{ //如果左子树为空,则只需重接其右子树
q = p;
p = p->rchild ;
free(q);
}
else if(!p->rchild)
{ //如果右子树为空,则只需重接其左子树
q = p;
p = p->lchild;
free(q);
}
else
{ //如果左右子树都不为空,采取修改左子树的方法,也可以修改右子树,方法类似
q = p;
s = p->lchild; //取待删节点的左节点
while(s->rchild)
{ //找到中序遍历时会得到的直接前驱
q = s;
s = s->rchild;
}
//用s来替换待删节点p
p->data = s->data;
//根据情况,将s的左子树重接到q上
if(p != q)
q->rchild = s->lchild;
else
q->lchild =s->lchild;
free(s);
}
}
bool delete_BSTree(BSTree &T,int key)
{
//不存在关键字为key的节点
if(!T)
return false;
else
{
if(SearchBST(T,key)) //查找到关键字为key的节点
{
//delete_Node1(T);
delete_Node2(T);
return true;
}
else
{
cout<<"查无此值~"<<endl;
return false;
}
}
}
void CreateBST(BSTree &T) {
T=NULL;
ElemType e;
cout << "请输入值:0结束"<<endl;
cin >> e.key;
while (e.key!=0) {
InsertBST(T,e);
cout << "请继续输入"<<endl;
cin>>e.key;
}
}
void destroy_BSTree(BSTree pTree) //递归销毁二叉排序树
{
if(pTree)
{
if(pTree->lchild)
destroy_BSTree(pTree->lchild);
if(pTree->rchild)
destroy_BSTree(pTree->rchild);
free(pTree);
pTree = NULL;
}
}
static BSTree SingleRotateWithLeft(BSTree pNode) //LL型
{
BSTNode *pNode1;
pNode1 = pNode->lchild;
pNode->lchild = pNode1->rchild;
pNode1->rchild = pNode;
/*结点的位置变了, 要更新结点的高度值*/
pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
pNode1->nHeight = Max(Height(pNode1->lchild), pNode->nHeight) + 1;
return pNode1;
}
static BSTree SingleRotateWithRight(BSTree pNode) //RR型
{
BSTNode *pNode1;
pNode1 = pNode->rchild;
pNode->rchild = pNode1->lchild;
pNode1->lchild = pNode;
/*结点的位置变了, 要更新结点的高度值*/
pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
pNode1->nHeight = Max(Height(pNode1->rchild), pNode->nHeight) + 1;
return pNode1;
}
static BSTree DoubleRotateWithLeft(BSTree pNode) //LR型
{
pNode->lchild = SingleRotateWithRight(pNode->lchild);
return SingleRotateWithLeft(pNode);
}
static BSTree DoubleRotateWithRight(BSTree pNode)
{
pNode->rchild = SingleRotateWithLeft(pNode->rchild); //RL型
return SingleRotateWithRight(pNode);
}
//int main(){
// BSTree T;
// CreateBST(T);
// cout<<"删除前"<<endl;
// cout<<"先序遍历:";
// PreOrder(T);
// cout<<endl<<"中序遍历:";
// InOrder(T);
// cout<<"请输入删除的关键字"<<endl;
// int i;
// cin>>i;
// while (i!=0) {
// delete_BSTree(T,i);
// InOrder(T);
// cout << "请继续输入"<<endl;
// cin>>i;
// }
// cout<<"删除后"<<endl;
// InOrder(T);
// return 0;
//}
int main()
{
int i;
ElemType e;
BSTree T = NULL;
srand((unsigned int)time(NULL));
for (i = 0; i < 10; ++i)
{
e.key = rand()%100+1;
printf("%d\n", e.key);
InsertBST(T,e);
}
cout<<"先序遍历:";
PreOrder(T);
cout<<endl<<"中序遍历:";
InOrder(T);
destroy_BSTree(T);
return 0;
}
运行结果:
随机产生10个数字构建平衡二叉树,重复的产生值当然是插不进去的。
由运行结果的先序遍历和中序遍历可推导出这颗二叉树为:
可知构建的二叉树是平衡二叉树。