二叉排序树
一、概念
基础概念:二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
- 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
- 左、右子树也分别为二叉排序树;
通俗理解:
- 查找过程有点像二分查找,都只需要O(logn)。 但是是以“链表”形式存储的二分查找,所以插入过程只需要在末尾添加新元素,而不需要去移动元素。提高了插入的速度
局限性:
由于二叉排序树的“不平衡”,所以在一些特定的情况下,会退化成单链表。 所以后来才会出现了二叉平衡树、红黑树,这种在二叉排序树的基础上,增加了平衡限定条件的特殊二叉排序树。
二、代码及过程
/**
*
*二叉排序树
*Data:2019年5月11日
*
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct treeNode{
int val;
treeNode *left,*right;
}treeNode,*tree;
// 查找节点
int searchNode(tree T,int key,tree f,tree &p){
if(T == NULL){ // 未找到
p = f;
return -1;
}
if(T->val == key){ // 找到当前节点
return 1;
}
else if(T->val < key){ // 要查找的值大于当前节点,在右子树查找
return searchNode(T->right,key,T,p);
}else{
return searchNode(T->left,key,T,p); // 在左子树查找
}
}
// 插入节点
int insertNode(tree &T,int key){
tree p;
// 未找到该节点,执行插入操作
if(searchNode(T,key,NULL,p) == -1){
tree node = (treeNode*)malloc(sizeof(treeNode));
node->val = key;
node->left = node->right = NULL;
if(p == NULL){ //被插入的节点为根节点
T = node;
}
// 要插入的节点大于当前节点,则在右子树
else if(key > p->val){
p->right = node;
}else{ // 在左子树
p->left = node;
}
return 1;
}else{
// 存在该节点,直接返回
return -1;
}
}
// 删除节点的操作
int deleteAction(tree &T,int key){
tree p,q,s;
p = T;
// 分三种情况讨论
// 1.如果左孩子为空,则直接让右孩子顶替当前节点
if(T->left == NULL){
T = T->right;
free(p);
return 1;
}
// 2.如果右孩子为空,同理
else if(T->right == NULL){
T = T->left;
free(p);
return 1;
}
// 3.如果左右孩子都不为空
else{
s = T->left;
q = s;
// 找到次小于当前节点的值
while(s->right != NULL){
q = s;
s = s->right;
}
if(q != s){
T->val = s->val;
q->right = s->left;
}else{
T->val = s->val;
T->left = q->left;
}
return 1;
}
// 删除失败
return -1;
}
// 删除节点
int deleteNode(tree &T,int key){
// 未找到要删除的节点
if(T == NULL){
return -1;
}
// 查找删除节点位置
if(T->val == key){
// 执行删除操作
return deleteAction(T,key);
}
else if(key < T->val){
return deleteNode(T->left,key);
}
else{
return deleteNode(T->right,key);
}
}
// 输出节点
void show(tree T){
if(T == NULL){
return;
}
show(T->left);
printf("%3d",T->val);
show(T->right);
}
void main(){
tree T = NULL;
tree p;
int n,key;
do{
show(T);
printf("\n**************************************\n");
printf("\n请输入操作: 1.查找 2.插入 3.删除 0.退出\n");
scanf("%d",&n);
switch(n){
case 1: printf("\n请输入要查找的值:");
scanf("%d",&key);
if(searchNode(T,key,NULL,p) == -1){
printf("\n未找到该节点!\n");
}else{
printf("\n查找成功!\n");
}
break;
case 2: printf("\n请输入要插入的值:");
scanf("%d",&key);
insertNode(T,key);
break;
case 3: printf("\n请输入要删除的值:");
scanf("%d",&key);
deleteNode(T,key);
break;
}
}while(n != 0);
}
三、复杂度
平均时间复杂度: O(nlogn)
空间复杂度: O(n)