排序二叉树
排序二叉树是一种如下定义的树:
(1)根结点的值比它的左子树上的任意一个结点的值都要大。
(2)根结点的值比它的左子树上的任意一个结点的值都要小。
(3)根的左子树和右子树也满足上述性质。
排序二叉树的先序遍历可以得到数据的升序序列。
1、排序二叉树的构造(插入)
构造排序二叉树的过程相对简单.
1 .从根结点开始,判断当前节点是否为空,若为空则执行插入操作。若非空则转第2步。
2.若根结点的值大于(小于)需要插入的值,递归根结点的左(右)孩子,转第1步。
代码实现c++
void insert_data(node *&head ,int value)
{
if (head == NULL)
{
node *tree = new node;
tree->data = value;
head = tree;
}
else
{
if(value < head->data)insert_data(head->left, value);
else insert_data(head->right, value);
}
}
2、排序二叉树的删除
排序二叉树的删除相比麻烦,因为有多种情况要考虑。
(1)最简单的情况:需要删除的结点时叶子结点(没有任何孩子),则直接删除
(2)需要删除的结点有一个孩子,那么让其父结点对应的指针指向被删除结点的孩子即可。
(3)需要删除的结点有两个孩子,那么可以如下操作:在两个孩子中选择一个作为父结点,将另一个孩子放到它的子树中。
代码实现 c++
注:
(1)笔者使用了循环的方法来查找对应元素,没有使用递归。
(2)根节点和非根节点分开讨论了,所以代码有点长。
(3)关于前面的选择,笔者通过判断左孩子的右深度和右孩子的左深度,选取深度小的为新的父结点。将深度大的拼接至深度小的结点的子树中。
//该结构体用来返回深度的值和最深处的结点
struct node_and_depth
{
struct node *a=NULL;
int depth=0;
};
//获得结点的右深度
void letf_big_depth(node *d,node_and_depth *r)
{
if (d == NULL)return;
else
{
r->depth++;
r->a = d;
letf_big_depth(d->right, r);
}
}
//获取结点的左深度
void right_small_depth(node *d,node_and_depth *r)
{
if (d == NULL)return;
else
{
r->depth++;
r->a = d;
right_small_depth(d->left, r);
}
}
上面的代码如果不考虑选择的问题,可以无视。
注意,因为懒~~所以所有情况都使用return语句作为退出口(没有使用递归),可能讲究代码规范的人会很恼火。。。
struct node* delete_data(node *head,int value)//按值删除结点
{
node *p = head;
if (head==NULL)
{
cout<<"error :tree is empty"<<endl;
return head;
}
node * father = NULL;//指向当前结点的父节点
while (head->data != value)//通过循环找到对应节点
{
father = head;
if (head->data > value)head = head->left;
else head = head->right;
if(head == NULL)
{
cout<<"the value is not exist "<<endl;
return p;
}
}
if (father == NULL)//删除的是根节点
{
if (head->left != NULL && head->right !=NULL)//删除的结点同时有左孩子和右孩子
{
struct node_and_depth *lr = new node_and_depth;
struct node_and_depth *rr = new node_and_depth;
letf_big_depth(head->left,lr);
right_small_depth(head->right,rr);
if (lr->depth >= rr->depth)//左子树深,故将左子树插入右子树的左孩子上
{
rr->a->left = head->left;
p = head->right;
delete head;
}
else
{
lr->a->right = head->right;
p = head->left;
delete head;
}
return p;
}
else
{ if (head->left == NULL && head->right == NULL)
{
delete head;
return NULL;
}
else
{
if (head->left != NULL)
{
node *temp = head->left;
delete head;
return temp;
}
else
{
node *temp = head->right;
delete head;
return temp;
}
}
}
}
if (head->left == NULL && head->right == NULL)//删除的是叶子结点
{
if (father->left->data == head->data)//确定该节点是父节点的左孩子还是右孩子
{
father->left = NULL;
delete head;
}
else
{
father->right = NULL;
delete head;
}
return p;
}
if (head->left != NULL && head->right !=NULL)//删除的结点同时有左孩子和右孩子
{
struct node_and_depth *lr = new node_and_depth;
struct node_and_depth *rr = new node_and_depth;
letf_big_depth(head->left,lr);
right_small_depth(head->right,rr);
if (father->left == head)//确定该节点是父节点的左孩子还是右孩子
{
if (lr->depth >= rr->depth)//左子树深,故将左子树插入右子树的左孩子上
{
father->left = head->right;
rr->a->left = head->left;
delete head;
}
else
{
father->left = head->left;
lr->a->right = head->right;
delete head;
}
}
else
{
if (lr->depth >= rr->depth)//左子树深,故将左子树插入右子树的左孩子上
{
father->right = head->right;
rr->a->left = head->left;
delete head;
}
else
{
father->right = head->left;
lr->a->right = head->right;
delete head;
}
}
return p;
}
//下面是只有一个孩子的
if (father->left->data == head->data)//确定该节点是父节点的左孩子还是右孩子
{
if (head->left != NULL)
{
father->left = head->left;
delete head;
}
else
{
father->left = head->right;
delete head;
}
}
else
{
if (head->left != NULL)
{
father->right = head->left;
delete head;
}
else
{
father->right = head->right;
delete head;
}
}
return p;
}
如有错误,欢迎指正!