目录
1、二叉排序树
1.1 定义
1.2 查找操作
1.3 插入操作
1.4 删除操作
1.5 C语言实现二叉排序树的基本操作
2、平衡二叉树的知识点总结
2.1 定义
2.2 插入操作
2.3 调整“不平衡”
2.4 删除操作
二叉排序树(Binary Search Tree,BST)是一种二叉树,具有如下性质:
1.若任意节点的左子树不为空,则左子树上所有节点的值小于它的根节点的值。
2.若任意节点的右子树不为空,则右子树上所有节点的值大于它的根节点的值。
3.任意节点的左、右子树都是二叉排序树。
4.没有键值相等的节点。
5.中序遍历二叉排序树可以得到一个有序的序列。
其中,左子树节点值小于根节点值,右子树节点值大于根节点值的性质,保证了二叉排序树的查找、插入、删除操作的时间复杂度为 O(log n)。
在 BST 中查找一个节点,可以按照以下步骤进行:
//查找值为key的结点
BSTNode* BST_Search(BSTree T, int key){
if(T == NULL || T->data == key)
return T;
else if(key < T->data)
return BST_Search(T->lchild, key);
else
return BST_Search(T->rchild, key);
}
找到应该插入的位置(一定是叶子结点),一定要注意修改其父节点指针。
//插入值为key的结点
BSTree BST_Insert(BSTree T, int key){
if(T == NULL){
T = (BSTNode*)malloc(sizeof(BSTNode));
T->data = key;
T->lchild = NULL;
T->rchild = NULL;
return T;
}
else if(key < T->data)
T->lchild = BST_Insert(T->lchild, key);
else if(key > T->data)
T->rchild = BST_Insert(T->rchild, key);
return T;
}
二叉排序树的删除操作可以分为以下几个步骤:
找到要删除的节点,并确定其父节点。
如果要删除的节点是叶子节点,直接删除即可,在其父节点中将其对应的子节点指针设为 null。
如果要删除的节点只有一个子节点,将其子节点代替要删除的节点,即在其父节点中将其对应的子节点指针指向其子节点。
如果要删除的节点有两个子节点,需要找到其右子树中的最小节点或者左子树中的最大节点,用该节点代替要删除的节点,并将其删除。如果选择右子树中的最小节点代替要删除的节点,需要从该节点的父节点开始,一直向左遍历,直到找到最后一个左节点,将其指向右子节点(因为要删除该节点)。如果选择左子树中的最大节点代替要删除的节点,需要从该节点的父节点开始,一直向右遍历,直到找到最后一个右节点,将其指向左子节点。
删除节点后,需要对二叉排序树进行调整,使其依然满足二叉排序树的性质。
//删除值为key的结点
BSTree BST_Delete(BSTree T, int key){
BSTNode *temp;
if(T == NULL)
return NULL;
else if(key < T->data)
T->lchild = BST_Delete(T->lchild, key);
else if(key > T->data)
T->rchild = BST_Delete(T->rchild, key);
else if(T->lchild && T->rchild){
temp = BST_FindMin(T->rchild);
T->data = temp->data;
T->rchild = BST_Delete(T->rchild, T->data);
}
else{
temp = T;
if(T->lchild == NULL)
T = T->rchild;
else if(T->rchild == NULL)
T = T->lchild;
free(temp);
}
return T;
}
#include
#include
//二叉排序树结点
typedef struct BSTNode{
int data; //数据域
struct BSTNode *lchild; //左子树指针
struct BSTNode *rchild; //右子树指针
}BSTNode, *BSTree;
//返回当前二叉树的高度
int GetHeight(BSTree T){
if(T == NULL)
return 0;
int left_height = GetHeight(T->lchild);
int right_height = GetHeight(T->rchild);
return left_height > right_height ? left_height+1 : right_height+1;
}
//查找值为key的结点
BSTNode* BST_Search(BSTree T, int key){
if(T == NULL || T->data == key)
return T;
else if(key < T->data)
return BST_Search(T->lchild, key);
else
return BST_Search(T->rchild, key);
}
//插入值为key的结点
BSTree BST_Insert(BSTree T, int key){
if(T == NULL){
T = (BSTNode*)malloc(sizeof(BSTNode));
T->data = key;
T->lchild = NULL;
T->rchild = NULL;
return T;
}
else if(key < T->data)
T->lchild = BST_Insert(T->lchild, key);
else if(key > T->data)
T->rchild = BST_Insert(T->rchild, key);
return T;
}
//找到以p结点为根节点的子树中最小结点
BSTNode* BST_FindMin(BSTNode *p){
if(p == NULL)
return NULL;
else if(p->lchild == NULL)
return p;
else
return BST_FindMin(p->lchild);
}
//删除值为key的结点
BSTree BST_Delete(BSTree T, int key){
BSTNode *temp;
if(T == NULL)
return NULL;
else if(key < T->data)
T->lchild = BST_Delete(T->lchild, key);
else if(key > T->data)
T->rchild = BST_Delete(T->rchild, key);
else if(T->lchild && T->rchild){
temp = BST_FindMin(T->rchild);
T->data = temp->data;
T->rchild = BST_Delete(T->rchild, T->data);
}
else{
temp = T;
if(T->lchild == NULL)
T = T->rchild;
else if(T->rchild == NULL)
T = T->lchild;
free(temp);
}
return T;
}
//中序遍历二叉排序树
void InOrder(BSTree T){
if(T == NULL)
return;
InOrder(T->lchild);
printf("%d ", T->data);
InOrder(T->rchild);
}
int main(){
BSTree T = NULL;
T = BST_Insert(T, 50);
T = BST_Insert(T, 20);
T = BST_Insert(T, 60);
T = BST_Insert(T, 10);
T = BST_Insert(T, 30);
T = BST_Insert(T, 55);
T = BST_Insert(T, 70);
printf("原始二叉排序树:");
InOrder(T);
printf("\n");
T = BST_Delete(T, 60);
printf("删除结点 60 后的二叉排序树:");
InOrder(T);
printf("\n");
return 0;
}
在上面的代码中,我们首先定义了一个二叉排序树结点,包括数据域和左右子树指针。然后实现了查找、插入、删除等操作。具体实现时,我们用了递归的方式来实现这些操作。最后,我们测试了一下二叉排序树的删除操作,输出了删除结点后的二叉排序树。
平衡二叉树(Balanced Binary Tree)是一种二叉查找树,其中每个结点的左右子树高度差至多为1。也就是说,对于任意结点,其左右子树高度的差不大于1。在平衡二叉树中,最小的叶子结点离根节点的距离不超过最大叶子结点离根节点的距离的1倍。这样可以保证树的高度始终在logn范围内,查找、插入、删除节点的时间复杂度为O(logn)。平衡二叉树的常见实现有AVL树、红黑树等。
和二叉树的插入一样,找到合适的位置插入,但是新插入的结点可能导致其祖先们平衡因子改变,导致失衡。
当一个节点的左子树高度和右子树高度的差值超过1时,就会导致平衡二叉树不平衡。解决这种不平衡的方法是通过旋转操作来调整平衡,以下是两种常用的旋转操作:
左旋操作:当某个节点的右子树比左子树高度大时,需要将节点向左旋转,使其右子树的左子树成为该节点的右子树,而该节点成为新的右子树的根节点。
右旋操作:当某个节点的左子树比右子树高度大时,需要将节点向右旋转,使其左子树的右子树成为该节点的左子树,而该节点成为新的左子树的根节点。
在进行旋转操作时,需要注意保持平衡因子的值正确。旋转操作是平衡二叉树实现自平衡的关键。
平衡二叉树的删除可以分为以下几个步骤:
1. 找到要删除的节点。如果要删除的节点是叶子节点或只有一个子节点,直接删除即可。
2. 如果要删除的节点有两个子节点,则需要找到它的后继节点或前驱节点来替换它。后继节点即右子树中最小的节点,前驱节点即左子树中最大的节点。
3. 如果替换节点也有子节点,则将替换节点的子节点与它的父节点相连。
4. 更新被删除节点的父节点的平衡因子,并从该节点开始向根节点遍历,查找是否存在平衡因子为2或-2的节点。如果存在,则进行旋转操作。
5. 最后,删除该节点并返回根节点。
平衡二叉树的删除操作较为复杂,需要保证删除后仍然是一棵平衡二叉树。