二叉排序树/AVL树原理与实现
2020/7/15
学习内容:
二叉树查找树原理和实现:
二叉查找树是特殊的二叉树,其中左子树的key值都小于根节点key值,右子树key值都大于根节点key值,对于每个子树,也是一颗二叉查找树。
二叉树查找树的构建:
typedef struct Node{
int key;
int data;
struct Node *lchild, *rchild;
}node;
node *getNewNode(int key) {
node *p = (node *)malloc(sizeof(node));
p->key = key;
p->lchild = p->rchild = NULL;
return p;
}
二叉树查找树的插入:
//返回插入后的根节点
node *insert(node *root, int key) {
if (root == NULL) return getNewNode(key);
if (root->key == key) return root;
if (root->key > key) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
return root;
}
二叉查找树的销毁:
void clear(node *root) {
if (root == NULL) return;
clear(root->lchild);
clear(root->rchild);
free(root);
return;
}
二叉树查找树的删除:
//返回删除后的根节点
node *erase(node *root, int key) {
if (root == NULL) return NULL;
if (key < root->key) {
root->lchild = erase(root->lchild, key);
} else if (key > root->key) {
root->rchild = erase(root->rchild, key);
} else {
if (root->lchild == NULL || root->rchild == NULL) {
node *p = root->lchild ? root->lchild : root->rchild;
free(p); //均为NULL时,p为NULL
return p;
} else {
node *p = predecessor(root);//找到root的前驱节点
root->key = p->key;
root->child = erase(p, p->key);//删除前驱节点
}
}
}
AVL树原理和实现:
AVL树通过左右子树的相对高度来判断树是否平衡,根据失衡的情形可以分为四种情况。
LL,LR,RL,RR。
AVL树的构建:
#define K(n) ((n) ? (n)->key : 0)
#define H(n) ((n) ? (n)->h : 0)
#define R(n) ((n) -> rchild)
#define L(n) ((n) -> lchild)
typedef struct Node{
int key;
int data;
int h; //用于保存树高的信息
struct Node *lchild, *rchild;
}node;
node *getNewNode(int key) {
node *p = (node *)malloc(sizeof(node));
p->key = key;
p->rchild = p->lchild = NULL;
p->h = 1;
return p;
}
AVL树的插入
//返回插入后的根节点
node *insert(node *root, int key) {
if (root == NULL) return getNewNode(key);
if (root->key == key) return root;
if (root->key > key) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
update_height(root);
return maintain(root);
}
AVL树的调整
//更新树的高数
//取左右子树中最高的加1
void update_height(node *root) {
root->h = (H(L(root)) > H(R(root)) ? H(L(root)) : H(R(root))) + 1;
return;
}
//AVL树的调整 返回调整之后的根节点
node *maintain(node *root) {
if (abs(H(L(root)) - H(R(root))) <= 1) return root; //不需要调整
if (H(L(root)) > H(R(root))) { //L型调整,LL右旋,LR先左旋后右旋
if (H(R(L(root))) > H(L(L(root)))) {//LR型
root->lchild = left_rot(root->lchild);
}
root = right_rot(root);
} else {
if (H(L(R(root))) > H(R(R(root)))) {//LR型
root->rchild = right_rot(root->rchild);
}
root = left_rot(root);
}
}
//左旋
node *left_rot(node *root) {
node *p = root->rchild;
root->rchild = p->lchild; //左孩子变右孩子
p->lchild = root;
update_height(root);
update_height(p);
return p;
}
//右旋
node *right_rot(node *root) {
node *p = root->lchild;
root->lchild = p->rchild;
p->rchild = root;
update_height(root);
update_height(p);
return p;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统