您的位置:首页 > 其它

二叉树的操作

2015-12-21 22:00 387 查看
二叉树是最多有两个孩子节点的类型的树

二叉树的思想延伸有很多,最经典的就是二分查找了,还有就是用决策树来判断比较排序的最优时间复杂度。等等。我就把不一一列举了(囧~当然也列举不完)。

今天用了将近半天的时间把二叉树的很多操作都实现了一下。有些非递归的真的是不好做,也不是很好想,开始做前序非递归我绞尽脑汁~~想了很久也没有想出来,后来大多都是听老师或者百度后才知道原来是这么写的。其实非递归写的真的不多,毕竟c语言短小精悍!但是要真正掌握c的要义以后还是要多多加强练习,希望以后自己可以能够自己想出来做出来。

由于代码比较多,(其实我觉得多,毕竟太多大家也找不到重要的)本文全部写递归思想

下一篇会补上其他的非递归。

闲言少叙,开始正式的代码之旅:

1.建树:这个是方法老师给我们讲的,和之前网上看到的略有不同之处

二叉树是一棵最多只有两个孩子节点类型的树。

很多算法都是可以用二叉树来描述,最经典的莫非二分查找算法了。二叉树还可以用作决策树

//创建节点
static Tree_node *create_node(void)
{
Tree_node *node = (Tree_node *)Malloc(sizeof(Tree_node));

bzero(node,sizeof(Tree_node));//是库函数strings.h(是的你没有看错,后面有s)的函数。作用是把n个数据块清0
return node;
}
//注意使用二级指针,因为如果传*str这个字符串,递归回退的时候参数str指向
//没有变化。只有使用二级指针,使得指向发生变化,才能让它向后移动。
Tree create_tree(const char **str)
{
//根据字符串创建一个二叉树
//a#bc##d##
//       a
//        \
//         b
//        / \
//       c   d
//先让根为NULL,如果不是'#'那么在创建节点并且赋值
Tree root = NULL;

if(**str != '#' && str != NULL && *str != NULL){
root = create_node();
root->ele = **str;

//指针指向字符串的下一个位置,然后创建左子树
++*str;
root->left = create_tree(str);
//如果为'#'就转到这里,创建右子树。
++*str;
root->right = create_tree(str);
}

return root;
}
2.销毁

void destroy_tree(Tree *root)
{
if(*root){
destroy_tree(&(*root)->left);
destroy_tree(&(*root)->right);
free(*root);
*root = NULL;
}
}


3.递归遍历

//遍历
void pre_order_print(Tree root)//先序
{
if(root == NULL){
return ;
}
if(root){
printf("%c ",root->ele);
pre_order_print(root->left);
pre_order_print(root->right);
}
}
void mid_order_print(Tree root)//中序
{
if(root){
mid_order_print(root->left);
printf("%c ",root->ele);
mid_order_print(root->right);
}
else{
return ;
}
}
void last_order_print(Tree root)//后序
{
if(root){
last_order_print(root->left);
last_order_print(root->right);
printf("%c ",root->ele);
}
else
return ;
}


4.递归求高度

int Tree_height(Tree root)//树的高度
{
if(root == NULL){
return -1;
}

return MAX(Tree_height(root->left),
Tree_height(root->right))+1;
}


5.递归求节点个数
int Tree_node_count(Tree root)//节点数
{
if(root == NULL){
return 0;
}

return Tree_node_count(root->left) + Tree_node_count(root->right) + 1;
}


6.递归求叶子节点个数

int Tree_leaf_count(Tree root)//叶子节点数
{
if(root == NULL){
return 0;
}
if(root->left == NULL && root->right == NULL){
return 1;
}

return Tree_leaf_count(root->left) + Tree_leaf_count(root->right);
}


7.树的镜像。就是把树变成对称的

比如     a                                      a

            /   \         ------->              /    \

          c     b                               b     c

void Tree_iso(Tree root)   //树的镜像
{
if(root == NULL){
return ;
}
//因为节点有可能指向的是NULL,所以交换节点首地址,所以就需要用
//指向节点首地址的指针。
if(root->left || root->right){
swap(&(root->left),&(root->right),sizeof(Tree_node *));
}
if(root->left){
Tree_iso(root->left);
}
if(root->right){
Tree_iso(root->right);
}
}


8.某一层有多少节点

int level_count(Tree root,int level)//某层的节点数目
{
if(root == NULL){
return 0;
}
if(level == 1){
return 1;
}

return level_count(root->right,level-1) +
level_count(root->left,level-1);
}


9.找两个节点最近的相同祖先

Tree_node *find_common_node(Tree root,Tree_node *node1,Tree_node *node2)
{
Tree_node *node1_ancestor;
Tree_node *node = NULL;

//如果root为空或节点就是root,那么返回空
if(node1 == root || node2 == root || root == NULL){
return NULL;
}
//找节点1的父节点
node1_ancestor = find_parent(root,node1);
//如果节点1的父节点的下面路径中并不包含节点2.就继续找父节点的父节点。
//直到包含为止,返回这个节点就是公共节点
while(node == NULL){
node = find_node(node1_ancestor,node2->ele);
if(node == NULL){
node1_ancestor = find_parent(root,node1_ancestor);
}
}
if(node1_ancestor == node2){
node1_ancestor = find_parent(root,node2);
}

return node1_ancestor;
}


10.一个树是否包含另一个树

//判断root1是否包含root2
Boolean is_tree_included(Tree root1,Tree root2)
{
//因为一个为空另一个不为空,那么它们的节点肯定不好判断
//所以root2只要先于root1截至就先让它返回真
//之后在通过root2中的每个节点是否与之对应来判断是否包含
if(root2 == NULL){
return TRUE;
}
if(root1 == NULL && root2 != NULL){
return FALSE;
}
if(root1->ele == root2->ele){
return TRUE;
}

return is_tree_included(root1->left,root2->left) &&
is_tree_included(root1->right,root2->right);
}


11.树的最长路径

int largest_dis(Tree root)
{
int distance = 0;
int way = 0;
int tmp = 0;

if(root == NULL){
return 0;
}

way = Tree_height(root->left) + Tree_height(root->right) + 2;
tmp = MAX(way, largest_dis(root->left));
distance = MAX(tmp, largest_dis(root->right));

return distance;
}

12根据中序和前序遍历的字符串得到树

//根据前序和中序确定一个树
Tree create_tree_by_pre_mid(char *pre_str,char *mid_str,int length)
{
int index = -1;
Tree root = NULL;

if(mid_str == NULL || pre_str == NULL || length <= 0){
return NULL;
}
root = create_node();
root->ele = pre_str[0];
index = get_index(mid_str,pre_str[0]);
root->left = create_tree_by_pre_mid(pre_str+1,mid_str,index);
root->right = create_tree_by_pre_mid(pre_str+index+1,
mid_str+index+1,length-index-1);

return root;
}

13.根据中序和后序得到树
Tree create_tree_by_last_mid(char *last_str,char *mid_str,int length)
{
Tree root = NULL;
int index = -1;

if(last_str == NULL || mid_str == NULL || length <= 0){
return NULL;
}
root = create_node();
//找到根节点在中序字符串中的位置。并赋值给新子树的根节点
index = get_index(mid_str,last_str[length-1]);
root->ele = last_str[length-1];

//递归对右子树左子树进行相同操作
root->left = create_tree_by_last_mid(last_str,mid_str,index);
root->right = create_tree_by_last_mid(last_str+index,mid_str+index+1,
length-index-1);
return root;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: