二叉排序树的基本操作: 1、查找 2、增加 3、删除。
代码展示及结果截图:
#include<stdio.h>
#include<stdlib.h>
/*
二叉排序树 <==> 二叉搜索树 (BST) <==> 二叉查找树
1. 二叉排序树的查找功能 (递归、非递归实现) --> 查找效率很大程度上取决于二叉排序树的高度。
2. 二叉排序树的插入功能 (默认不同元素的值才插入) --> 先查找再插入
3. 二叉排序树的删除功能 (两种实现方式, 1.后继结点顶上来,删除后继结点 2.前驱结点顶上来,删除前驱结点) --> 先查找再删除
4. 根据一个序列,构造二叉排序树的功能。 --> 其实就是遍历序列 插入二叉排序树。
二叉排序树的一个重要指标 : 平均查找长度(ASL)
平均查找长度又分: 查找成功的平均查找长度 sum(查找每个元素的比较次数)/元素个数
查找失败的平均查找长度 sum(查找每个失败元素时比较次数)/失败出现的可能数
结论: 二叉排序树最好尽可能平衡,因为这样的查找效率可以达到O(log n).
*/
#define ElemType int
#define null NULL
typedef struct BSTNode{
ElemType key;
struct BSTNode *lchild,*rchild;
}BSTNode;
//二叉搜索树查找功能的非递归实现 时间复杂度O(log n) - O(n)
BSTNode* findKey(BSTNode *t,ElemType value){ //最坏空间复杂度O(1)
//t == null 代表查找元素不存在
while(t != null && value != t->key){
if(t->key > value){
t = t->lchild;
}else{
t = t->rchild;
}
}
return t;
}
//二叉搜索树的查找功能(递归实现)
BSTNode* findKey2(BSTNode *t, ElemType value){ //最坏空间复杂度O(h) h是二叉搜索树的最大高度。
if(t == null){
return null;
}
if(t->key == value){
return t;
}
if(t->key > value){
return findKey2(t->lchild,value);
}else{
return findKey2(t->rchild,value);
}
}
//二叉搜索树的插入功能 (默认不同元素的值才插入)
bool BST_insert(BSTNode **t, ElemType value){
//插入第一个结点
if(*t == null){
BSTNode *s = (BSTNode *)malloc(sizeof(BSTNode));
s->key = value;
s->lchild = null;
s->rchild = null;
*t=s;
return true;
}
if(((*t)->key == value)){
return false;
}else if((*t)->key > value && (*t)->lchild == null){
BSTNode *s = (BSTNode *)malloc(sizeof(BSTNode));
s->key = value;
s->lchild = null;
s->rchild = null;
(*t)->lchild=s;
return true;
}else if((*t)->key < value && (*t)->rchild == null){
BSTNode *s = (BSTNode *)malloc(sizeof(BSTNode));
s->key = value;
s->lchild = null;
s->rchild = null;
(*t)->rchild=s;
return true;
}else{
//递归寻找
if((*t)->key > value){
BST_insert(&((*t)->lchild),value);
}else{
BST_insert(&((*t)->rchild),value);
}
}
}
//根据序列构造二叉搜索树
BSTNode* Creat_BST(ElemType str[],int n){
BSTNode *t = null; //初始时t为空树
for(int i = 0;i < n;i++){ //依次将每个关键字插入到二叉排序树中
BST_insert(&t,str[i]);
}
return t;
}
//二叉搜索树的删除功能
/*
1.删除的结点是叶子结点
2.删除的结点只有左子树或者只有右子树
3.删除的结点既有左子树又有右子树
*/
//value是要删除的元素值
//不应该找到要删除的元素,而是应该找到要删除元素的前一个元素。
BSTNode* BST_delete(BSTNode *b,ElemType value){
BSTNode *t = b;
//f指针指向的是要删除结点的双亲
BSTNode *f = null;
//判断t是f的哪个孩子(左孩子 or 右孩子)
int child = 0;
while(t != null && t->key != value ){
f=t;
if(t->key > value){
child = -1;
t= t->lchild;
}else{
child = 1;
t=t->rchild;
}
}
//没找到 删除失败
if(t == null){
return b;
}
//删除的是根节点,并且左右子树都没有
if(f == null && t -> rchild == null && t->lchild == null ){
b = null;
free(t);
return b;
}
//删除的是根节点,并且没有左子树,只有右子树
if(f == null && t->lchild == null && t->rchild != null){
b=t->rchild;
free(t);
return b;
}
//删除的是根节点,并且没有右子树,只有左子树
if(f == null && t->rchild == null && t->lchild != null){
b=t->lchild;
free(t);
return b;
}
//删除的是叶子结点
if(t->lchild == null && t->rchild == null){
free(t);
//删除的结点是他爹的左孩子
if(child == -1){
f->lchild = null;
}
if(child == 1){
f->rchild = null;
}
return b;
}
//删除的结点只有右子树,没有左子树
if(t->lchild == null && t->rchild != null){
//删除的结点是他爹的左孩子
if(child == -1){
f->lchild = t->rchild;
free(t);
}
if(child == 1){
f->rchild = t->rchild;
free(t);
}
return b;
}
//删除的结点只有左子树,没有右子树
if(t->lchild != null && t->rchild == null){
//删除的结点是他爹的左孩子
if(child == -1){
f->lchild = t->lchild;
free(t);
}
if(child == 1){
f->rchild = t->lchild;
free(t);
}
return b;
}
//删除的结点既有左子树又有右子树
if(t->lchild != null && t->rchild != null ){
//两种方式解决 1.将右子树中最小的元素放到此位置,并删除右子树中的最小元素。
// 2.将左子树中最大的元素放到此位置,并删除左子树中的最大元素。
//方式1代码
//右子树中最小的元素,就是右子树中最左下角的元素.
// BSTNode *q = t->rchild;
// while(q->lchild != null ){
// q = q->lchild;
//
// }
//q即为要查找的右子树的最小元素
//1
// ElemType temp = q->key;
//右子树中删除值最小的元素 , 先删除再赋值
//BST_delete(b,q->key);
//t->key = temp;
//2 巧妙的利用了返回值,无缝将右子树部分删除掉q并衔接。
// t->key = q->key;
// t->rchild = BST_delete(t->rchild,q->key);
//方式2代码
//左子树中最大的元素,就是左子树中最右下角的元素。
BSTNode *z = t->lchild;
while(z->rchild != null){
z = z->rchild;
}
//z即为要查找的左子树的最大元素
t->key = z->key;
t->lchild = BST_delete(t->lchild,z->key);
return b;
}
}
//二叉树的中序遍历
void in_order(BSTNode *t){
if(t != null){
in_order(t->lchild);
printf("%d ",t->key);
in_order(t->rchild);
}
}
int main(int argc, char *argv[])
{
ElemType str[] = {19,13,11,8,50,66,70,60,63,61,65,26,30,21};
BSTNode *m = Creat_BST(str,14);
in_order(m);
printf("\n");
BSTNode *end = BST_delete(m,70);
printf("\n");
in_order(end);
return 0;
}
注意:
二叉搜索树在插入删除一个结点的时候,不能单单只找到当前要插入结点的位置、要删除的结点。
还要找到要插入结点位置的前一个结点,要删除结点的父结点。因为无论是插入还是删除,父结点指针的指向都需要改变。