二叉搜索树
二叉搜索树也称二叉排序树或二叉查找树
储存模式:
1,非空左子树的所有键值小于根结点键值
2,非空右子树的所有键值大于根节点键值
3,左右子树都是二叉搜索树
查找元素:
循环实现:
position find (elementtype x,binTree bts){
while(bts){
if(x > bts->data) bts=bts->right;
else if(x < bts->data) bts=bts->left;
else return bts;
}
return NULL;
}
递归实现:
position find (elementtype x,binTree bts){
if(!bts)return NULL;
if(x > bts->data) return find(x,bts->right);
else if(x < bts->data) return find(x,bts->left);
else return bts;
}
循环实现比递归实现效率更快。
查找最大值:一直找右结点
position finMin(binTree bts){
if(!bts) return NULL;
else if (!bts->left) return bts;
else return finMin(bts->left);
}
查找最小值:一直找左结点
position finMax(binTree bts){
if(bts)
while(bts->right) bts=bts->bts->right;
return bts;
}
插入元素:
插入的元素x。
如果x大于结点就比较右子树,小于就比较左子树。
如果比较后结点所指为空,x大于该结点就插到
递归实现:
binTree insert(elementtype x,binTree bts){
if(!bts){
//若原树为空,生成并返回一个结点的二叉搜索树
bts=malloc(sizeof(struct treeNode));
bts->data=x;
bts->left=bts->right=NULL;
}else{
//查找插入元素的位置
//递归插入左子树
if(x < bts->data) bts->left=insert(x,bts->left);
//递归插入右子树
else if(x > bts->right) bts->right = insert(x,bts->right);
//else x=bts->data啥也不做
return bts;
}
}
删除元素:
binTree delete(elementtype x,binTree bts){
position tmp;
if(!bts)printf("meiyou");
else if(x < bts->data) bts->left = delete(x,bts->left);
else if(x > bts->data) bts->right = delete(x,bts->right);
//找到了删除的结点
else {
//被删除有左右两个元素
if(bts->left && bts->right){
//在右子树种找最小的元素填充删除
tmp=finMin(bts->right);
bts->data=tmp->data;
//在删除结点的右子树中删除最小元素
bts->right=delete(bts->data,bts->right);
}else{
//被删除结点有一个或无结点
tem=bts;
if(!bts->left){//有右孩子或无子节点
bts = bts->right;
}else if(!bts) bts=bts->left;//有左孩子或无子节点
free(tmp);
}
}
return bts;
}
平衡二叉树(Balanced Binary Tree)(AVL树)
平衡二叉树是搜索树/查找树,要保证左边小右边大。
平衡因子(Balance Factor,简称BF):BF(T)=h(左)-h(右)
h为树的高度。
平衡二叉树(Balanced Binary Tree):空树,或者
任一结点左右子树高度差的绝对值不超过1,即 | BF(T) | <= 1
那么n(h)是高度为h的平衡二叉树的最小结点是:如下公式。
给定结点数n,AVL树的最大高度为O(log₂n)。那么他的查找效率也就是O(log₂n)。
平衡二叉树的节点插入
平衡二叉树插入节点可能会破坏平衡。所以要对插入节点后的二叉树进行调整。且调整后仍要是平衡二叉树,依旧要左边小右边大。
调整主要是要考虑的是**以哪个节点为根节点的树被破坏了平衡。**也就是| BF |大于1了。
平衡二叉树所有破坏平衡的解决方法就是如下4种。
数据结构
typedef struct structnode *snode;
typedef struct structnode node;
structnode{
int val;//值
node *left;//左孩子
node *right;//右孩子
};
求高函数
//求树的高度的函数:i
ntdepth(node *root){
if(root==NULL) {return0; }
int dep1=depth(root->left);
int dep2=depth(root->right);
return (dep1>dep2?dep1:dep2)+1;
}
RR旋转(右单旋转)
RR旋转解决的是像下图插入1元素节点问题。
1不管是插在左还是右都用的是这个方法。将2领出来作为根结点。2的旋转方向是向右。
C语言代码
node *RightRotate(node *root){//右旋 RR
node *temp=root->left;
root->left=temp->right;
temp->right=root;
return temp;
}
LL旋转
C语言
node *LeftRotate(node *root){//左旋 LL
node *temp=root->right;
root->right=temp->left;
temp->left=root;
return temp;
}
LR旋转
c
//LR旋转代码如下:
node *LeftRightRotate(node *root){
//先对root的左子树左旋再对root右旋
root->left=LeftRotate(root->left);
return RightRotate(root);
}
RL旋转
c
//RL旋转代码如下:
node *RightLeftRotate(node *root){
//先对root的右子树右旋再对root左旋
root->right=RightRotate(root->right);
return LeftRotate(root);
}
插入函数
//插入
node *Insert(node *root,int v){
if(root==NULL) {
root=(snode)malloc(sizeof(struct structnode));
root->val=v;
root->left=NULL;
root->right=NULL;
}else {
if(v < root->val) {
//插到左子树上
root->left=Insert(root->left,v);
if(depth(root->left)-depth(root->right)>=2) {
//左边高右边低
if(v<root->left->val) {//右旋
root=RightRotate(root);
}else {//先对其左子树左旋再右旋
root=LeftRightRotate(root);
}
}
}else{//插到右子树上
root->right=Insert(root->right,v);
if(depth(root->right)-depth(root->left)>=2) {
if(v>root->right->val) {//左旋
root=LeftRotate(root);
}else {//先对其右子树右旋再左旋
root=RightLeftRotate(root);
}
}
}
}
return root;
}
红黑树
红黑树(Red Black Tree):是一种自平衡二叉树。红黑树的子树也是红黑树。红黑树是AVL树的变体,他的左右子树高度差可能大于1,所以严格意义上红黑树不是AVL树。
红黑树可以在O(log n)时间内做查找,插入和删除。
特征:
红黑树的每个结点都带有颜色属性,(红色或黑色)。有如下性质:
- 是二叉搜索树,具备二叉搜索树的性质
- 结点是红色或黑色
- 根结点和所有叶子结点是黑色。(叶子是NULL结点)
- 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
- 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点