二叉树是一个很重要的数据结构,关于树的相关操作,我想最重要的就是掌握树的遍历算法,其中的递归思想也是很难理解的,递归能化繁为简,将一些复杂的问题分解为一系列相同思想的小问题,但递归的不足之处是空间消耗大,需要不停的压栈出栈。
设 二叉树节点的结构
typedef struct node * tree_pointer;
typedef struct node{
tree_pointer left_child;
int value;
tree_pointer right_child;
};
1.二叉树的建立:
tree_pointer tree_built()
{
tree_pointer temp;
int val;
scanf("%d",&val);
if(val==-1) temp=NULL;
else{
temp=(tree_pointer)malloc(sizeof(node));
temp->value=val;
temp->left_child=tree_built();
temp->right_child=tree_built();
}
return temp;
}
2.二叉树的中序遍历:
void inorder(tree_pointer tree)
{
if(tree){
inorder(tree->left_child);
printf("%d ",tree->value);
inorder(tree->right_child);
}
}
二叉树的删除,遍历等其他操作都是建立在遍历的思想上
3.二叉树的的删除:
void del_tree(tree_pointer tree)
{
if(tree){
inorder(tree->left_child);
delete(tree);
inorder(tree->right_child);
}
}
4.二叉树的复制:
tree_pointer copy(tree_pointer original)
{
if(original){
temp=(tree_pointer) malloc(sizeof(node));
if(IS_FULL(temp)){
fprintf(stderr,"The memory if full\n");
exit(1);
}
temp->left_child=copy(original->left_child);
temp->right_child=copy(original->right_child);
temp->data=original->data;
return temp;
}
return NULL;
}
二叉查找树:满足
(1) 每个元素都有关键字,任意两个关键字都不相同。
(2) 非空左子树的关键字值一定小于其子树的根节点的关键字值。
(3) 非空右子树的关键字值一定大于其子树的根节点的关键字值。
定义很绕,翻译一下,对于二叉树中的任意节点,其右子树当中的所有关键字值都大于该节点,其左子树当中的所有关键字值都小于该节点的关键字值。
1.二叉查找树的查找
a.递归查找
tree_pointer search(tree_pointer root,int key)
{
if(!root) return NULL;
if(key==root->value) return root;
if(key<root->value)
return search(root->left_child,key);
return search(root->right_child,key);
}
b.迭代查找
tree_pointer search2(tree_pointer tree,int key)
{
while(tree){
if(key==tree->value) return tree;
if(key<tree->value)
tree=tree->left_child;
else
tree=tree->right_child;
}
return NULL;
}
二叉查找树的删除
删除可分为三种情况,1.删除的元素是叶子节点,可以直接删除,并将该节点的父节点的儿子域(原本被删除的节点的位置)置为NULL 2.删除的元素只有一个儿子,删除目标节点,并将其唯一的儿子节点取代原来的位置 3.含有两个孩子的节点,稍复杂点,首先用其左子树中的最大元素或者其右子树当中的最小元素替代该节点。若使用左子树当中的最大值来代替(此元素的度一定为0或者1,且其右子树为空)。若度为0(即为叶节点)则可以直接将该节点删除,并将其父节点的儿子域(被删除节点的位置)置为NULL;若度为1(此时只含一个左儿子),则将此节点的值置为其左儿子的值,然后删除左儿子,然后将该节点的左儿子置为NULL;
tree_pointer tr2del(tree_pointer tree,int key)
{
tree_pointer fi=search2(tree,key,0);
if(!fi) {printf("this act is wrong");exit(1);}
if((!fi->left_child)&&(!fi->right_child)) //叶节点时
{ tree_pointer fa=search2(tree,key,1);
if(fa==fi) { delete(fi);return NULL;} //树只有根节点
else{
printf(" %d\n",fi->value);
printf(" %d\n",fa->value);
if(fa->left_child==fi) fa->left_child=NULL;
if(fa->right_child==fi) fa->right_child=NULL;
delete(fi);
return tree;
}
}
if(fi->left_child&&(!fi->right_child)){ //只有左儿子
fi->value=fi->left_child->value;
fi->left_child=NULL;
delete(fi->left_child);return tree;}
if(fi->right_child&&(!fi->left_child)){ //只有右儿子
fi->value=fi->right_child->value;
fi->right_child=NULL;
delete(fi->right_child);return tree;}
if((fi->left_child)&&(fi->right_child)){ //度为2
tree_pointer temp=fi->left_child;
while(temp->right_child)
{
temp=temp->right_child;
}
fi->value=temp->value;
if(temp->left_child)
{temp->value=temp->left_child->value;
delete (temp->left_child);
temp->left_child=NULL;
}
else
delete temp;
return tree;
}
}
当中用到了二叉查找树的遍历查找程序,但稍做了些修改,因为程序当中要用到查找元素的父亲节点,所以添加了返回父亲节点的功能,当type=1时返回父亲节点。
程序编的感觉很不好,现在还很菜,等以后再来改善看看,注意每次判断后都要返回,因为每种情况下都改变了二叉树,改变结构后可能对下面的条件判断时造成还成立的影响。
<pre class="cpp" name="code"> tree_pointer search2(tree_pointer tree,int key,int type)
{
tree_pointer father=tree;
while(tree){
if(key==tree->value&&type) return father;
if(key==tree->value&&!type) return tree;
if(key<tree->value)
{ father=tree;
tree=tree->left_child;}
else
{ father=tree;
tree=tree->right_child;
}
}
return NULL;
}