二叉查找树(排序树):
定义:
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
一棵深度为k且有2k-1个结点的二叉树称为满二叉树。 可以对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,自左至右,则由此可引出完全二叉树的定义。深度为k且有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称之为完全二叉树。
#include<stdio.h>
#include<stdlib.h>
#define N 100
typedef struct node{
int data;
int deep;
struct node * left;
struct node *right;
}Node;
Node * root = NULL;
int node_num = 0;
int buf[N] ;
int insert_node(Node * root,int data);
Node * NewNode(int init){
Node *p;
p = (Node *)malloc(sizeof(Node));
p->data = init;
p->left = NULL;
p->right = NULL;
return p;
}
int buildtree(Node * r,int node_num){
int i = 0;
if(root == NULL){
root = NewNode(buf[0]);
}
for(i = 1;i < node_num;i++){
insert_node(root,buf[i]);
}
}
int insert_node(Node * Root,int data){
Node * p = Root;
Node *obj;
while(p != NULL){
obj = p;
if(p->data == data){
return 0;
}
p = (data < p->data ) ? p->left : p->right;
}
Node *temp = NewNode(data);
if(obj->data < data){
obj->right = temp;
}else{
obj->left = temp;
}
return 0;
}
int search_tree(Node * root){
if(root){
search_tree(root->left);
printf("%d ",root->data);
search_tree(root->right);
}
}
Node * findmin(Node * start){
if(start != NULL){
start = start->left;
}
return start;
}
Node * delete(Node * Root,int Data){
Node * temp;
if(Root == NULL){
return NULL;
}else{
if(Data < Root->data){
Root->left = delete(Root->left,Data);
}else{
if(Data > Root->data){
Root->right = delete(Root->right,Data);
}else{
if(Root->left && Root->left){
temp = findmin(Root->right);
Root->data = temp->data;
Root->right = delete(Root->right,Root->data);
}else{
temp = Root;
if(Root->left == NULL){
Root = Root->right;
}else if(Root->right == NULL){
Root = Root->left;
}
free(temp);
}
}
}
}
return Root;
}
int main(int argc, char **argv){
scanf("%d",&node_num);
printf("%d\n",node_num);
int i = 0;
for(i = 0;i < node_num;i++){
scanf("%d",&buf[i]);
}
buildtree(root,node_num);
search_tree(root);
return 0;
}
这里值得注意的是删除操作,如果目标节点只有一个儿子是很简单的。如果有两个儿子就会变得复杂一些。 我们这里放上一个图来表示。
此图从中间分开,第一层的两个图是描述对于只有一个儿子节点的4号节点的删除,很简单,使他的父亲节点指向自己的儿子节点就完成删除过程,但是第二种情况就稍微复杂,一般的删除策略是用其柚子树的最小的数据代替该结点的数据并且删除那个节点。如图2号节点被3号节点代替后,被删除。 注意:ADT树在频繁的插入删除操作中,会因为我们的删除策略导致整个树在向右下沉。树的平衡性被打破,我们当然可以随机的选取右子树的最小元素,或者左子树的最大元素来作删除工作,但是对于不大的树来说似乎又不是很明显的效果。ADT 毕竟只是平衡树的最简单思想。进一步的AVL树将进一步的解决这个问题。