简单的树的递归、非递归创建,前序中序后序遍历

扩展问题

问题1.给定前序遍历结果和中序遍历结果,重建二叉树

递归构造就可以了。

Tree* create_by_order(int* pre,int* in,int size){
    if(size<=0||pre==NULL||in==NULL){
        return NULL;
    }
    int i=0;
    Tree* rt = malloc(sizeof(Tree));    
    rt->value = pre[0];
//在中序中查找根节点位置
while(i<size){ if(pre[0]==in[i]){ break; }else{ i++; } } rt->left = create_by_order(pre+1,in,i); rt->right = create_by_order(pre+1+i,in+i+1,size-i-1); return rt; }

 

问题2.二叉树镜像

Tree* mirror(Tree* rt){
    if(rt!=NULL){
        //交换左右子树的指针 
        Tree* temp;
        temp = rt->right;
        rt->right = rt->left;
        rt->left = temp;
        
        rt->left = mirror(rt->left);
        rt->right = mirror(rt->right);    
    }
    return rt;
}

 

问题3.求二叉树节点最大距离

 

分三种情况

情况1.如第一个图所示,左深度加上右深度

情况2.如第二个图所示,左子树中节点的最大距离

情况3.将图二镜像一下,右子树中节点的最大距离

最后结果就是求这三个中较大的。

int depth(Tree* rt){
    if(rt!=NULL){
        int l_depth = depth(rt->left)+1;
        int r_depth = depth(rt->right)+1;
        return l_depth>r_depth ? l_depth:r_depth;    
    }
    return 0;
}

int max(int a,int b,int c){
    if(a>b&&a>c){
        return a;
    }
    if(b>a&&b>c){
        return b;
    }
    if(c>a&&c>a){
        return c;
    }
  return a; }
int max_distance(Tree* rt){ if(rt!=NULL){ int l_distance = max_distance(rt->left); int r_distance = max_distance(rt->right); int l_depth = depth(rt->left)+1; int r_depth = depth(rt->right)+1; return max(l_distance,r_distance,l_depth+r_depth); } return 0; }

 

 问题4.求两个节点的最近公共父节点(没有指向父节点指针,树为一般二叉树)

分三种情况

1.如果p1,p2节点分别在root->left,root->right,那么root为p1,p2的祖先

2.如果p1,p2都在root->left,那边将root=root->left 转换为子问题

3.如果p1,p2都在root->right, 那么将root=root->right 转换为字问题

/**
*** 查找树中包含某个节点 
**/
int contains(Tree* rt,const Tree* p){
    if( rt==p ){
        return 1;
    }
    if(rt==NULL){
        return 0;
    }
    return contains(rt->left,p)||contains(rt->right,p);
}

/**
***  查找P1和P2的最近公共父节点 
**/
Tree* get_same_parent(Tree* rt,const Tree* p1,const Tree* p2){
    if(rt==NULL){
        return NULL;
    }
    if(p1!=NULL&&p2!=NULL){
        int left_contains_p1 = contains(rt->left,p1);
        int left_contains_p2 = contains(rt->left,p2);
        int right_contains_p1 = contains(rt->right,p1);
        int right_contains_p2 = contains(rt->right,p2);
        if( left_contains_p1 && left_contains_p2 ){
            return get_same_parent(rt->left,p1,p2);
        }
        if( right_contains_p1 && right_contains_p2 ){
            return get_same_parent(rt->right,p1,p2);
        }    
        return rt;
    }        
}

 扩展,如果树是搜索树时

1.p1,p2小于root,root=root->left

2.p1,p2大于root, root=root->right

3.p1,p2在root两边,root为p1,p2的最近公共父节点

STree* get_same_parent(STree* rt,STree* p1,STree* p2){
    if(rt==NULL){
        return NULL;
    }
    if( rt->value > p1->value && rt->value > p2->value ){
        return get_same_parent(rt->left,p1,p2);
    }
    if( rt->value < p1->value && rt->value < p2->value ){
        return get_same_parent(rt->right,p1,p2);
    }
    return rt;
}

扩展,一般树

方法1.

用两个链表保存从根节点到p1,p2的路径。然后将问题转换为两个链表求交集问题。

方法2.

 转自:http://www.cppblog.com/qingbizhu/archive/2012/04/05/170213.html

 

问题5.二叉查找树的删除

待删除节点是叶子节点,直接删除

待删除节点只有左子树或者只有右子树 ,将左(右)子树节点位置替换到待删除节点位置

待删除节点既有左子树又有右子树,遍历到待删除节点的最左下节点位置,也就是找到一个比待删除节点小,但是小得最少的,然后将这个节点替换到待删除节点位置

c语言写着还挺带感

#include<stdlib.h>
#define null 0
struct tree{
    struct tree* left;
    int value;
    struct tree* right;
};

typedef struct tree Tree;
Tree* root;

Tree* insert_rcs(Tree* root, int value){            
    //只在叶节点位置插入 
    if(root == null){    
        root = malloc(sizeof(Tree));
        root->value = value;
        root->left = null;
        root->right = null;    
        //返回新增的叶节点 
        return root;
    }
    
    if(root->value > value){
        root->left = insert_rcs(root->left, value);
    }else{
        root->right = insert_rcs(root->right, value);
    }
    return root;
}

Tree* insert_no_rcs(Tree* root, int value){
    Tree* newnode = malloc(sizeof(Tree));
    newnode->value = value;
    newnode->left = null;
    newnode->right = null;
    if(root == null){
        root = newnode;
        return root;
    }
    //p为工作指针 
    Tree* p = root;
    //p节点是插入节点,pre节点时插入节点的父节点 
    Tree* pre;
    while(p){
        pre = p;
        if(p->value > value){
            p = p->left;
        }else{
            p = p->right;
        }    
    }
    if(pre->value > newnode->value){
        pre->left = newnode;
    }else{
        pre->right = newnode;
    }
    return root;    
}

//前序遍历 
void pre_print_rcs(Tree* root){
    if(root != null){
        printf("value: %d \t",root->value);
        pre_print_rcs(root->left);
        pre_print_rcs(root->right);
    }
}

Tree* Stack[20];
int top = -1;

//前序遍历 非递归 
void pre_print_no_rcs(Tree* root){
    //top != -1 这个条件一定要加上,这是处理单枝情况 
    while(root != null || top != -1){
        if(root != null){
            printf("%d \t",root->value);
            if(top+1 != 20){
                Stack[++top] = root;
                root = root->left;
            }
        }else{
            root = Stack[top--]->right;
        }    
    }
}

//中序遍历
void in_print_rcs(Tree* root){
    if(root != null){
        in_print_rcs(root->left);
        printf("value: %d \t",root->value);
        in_print_rcs(root->right);
    }
}

//中序遍历 非递归 
void in_print_no_rcs(Tree* root){
    //top != -1 这个条件一定要加上,这是处理单枝情况 
    while(root != null || top != -1){
        if(root != null){
            if(top+1 != 20){
                Stack[++top] = root;
                root = root->left;
            }
        }else{
            root = Stack[top--];
            printf("%d \t",root->value);
            root = root->right;
        }    
    }    
}

//后序遍历
void post_print_rcs(Tree* root){
    if(root != null){
        post_print_rcs(root->left);
        post_print_rcs(root->right);
        printf("value: %d \t",root->value);
    }
}

Tree* Q[20];
int front;
int rear;
//层序遍历 
//输出队头元素,并将左右子树如队列 
void level_print(Tree* root){
    front = rear = 0;
    if(root != null){
        Q[++rear] = root;
        while(rear != front){
            Tree* p = Q[++front];
            printf("%d \t",p->value);
            if(p->left != null){
                Q[++rear] = p->left;
            }
            if(p->right != null){
                Q[++rear] = p->right;
            }
        }
    }
}

Tree* create_no_rcs(int* list, int n){
    int i;
    for(i=0; i<n; i++){
        root = insert_no_rcs(root, list[i]);
    }
    return root;
}

Tree* create_rcs(int* list, int n){
    int i;
    for(i=0; i<n; i++){
        root = insert_rcs(root, list[i]);
    }
    return root;
}

int main(){
    int list[10] = {
        6,9,7,4,5,2,1,8,12,0
    };
    //root = create_no_rcs(list, 10);
     root = create_rcs(list, 10);
    
    //pre_print_rcs(root);
    //pre_print_no_rcs(root);
    in_print_rcs(root);
    in_print_no_rcs(root);
    //post_print_rcs(root);
    
    //level_print(root);
    
    return 0;
}

转载于:https://www.cnblogs.com/23lalala/archive/2012/09/26/2703646.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值