12、二叉树

1、二叉树的定义和初始化

//二叉树节点定义 
typedef struct BinTreeNode{
    ElemType data;
    struct BinTreeNode* leftChild;
    struct BinTreeNode* rightChild;
}BinTreeNode;

//二叉树定义 
typedef struct BinTree{
    BinTreeNode* root;
    ElemType refvalue; //结束标记 
}BinTree;

//初始化二叉树,并规定结束标记为 #
void initBinTree(BinTree* tree,ElemType ref){
    tree->root = NULL;
    tree->refvalue = ref; 
} 

2、二叉树的创建方式

// 创建二叉树方式1 [node 是二级指针 C++可以通过BinTreeNode*& node引用的简便写法]
void createBinTree_1(BinTree* bt,BinTreeNode** node){
    ElemType item;
    scanf("%c",&item);
    if(item == bt->refvalue)
        *node = NULL;
    else{
        (*node) = (BinTreeNode*) malloc(sizeof(BinTreeNode));
        assert(*node != NULL);
        //创建根
        (*node)->data = item; 
        //递归创建
        createBinTree_1(bt,&(*node)->leftChild);
        createBinTree_1(bt,&(*node)->rightChild);
    }
}

//创建二叉树方式2 通过返回根节点创建二叉树
BinTreeNode* createBinTree_2(BinTree* bt){
    ElemType item;
    scanf("%c",&item);
    if(item == bt->refvalue)
        return NULL;
    else{
        BinTreeNode* node = (BinTreeNode*) malloc(sizeof(BinTreeNode));
        assert(node != NULL);
        node->data = item;
        node->leftChild = createBinTree_2(bt);
        node->rightChild = createBinTree_2(bt);
        return node;
    }
} 
//创建二叉树方式3 根据字符串str创建二叉树
//此处是错误代码,原因:char* str  
//        1.createBinTree_3(bt,&(*node)->leftChild,++str);
//        2.createBinTree_3(bt,&(*node)->rightChild,++str);
//      在运行这两行代码时,如果 在运行1时又递归调用了 1 ,
//        str不会进行改变,也就说不会"+2",在回来运行2时还是+1的状态
//      所以此处不应该char* 想要改变一级指针的值就需要二级指针 
//void createBinTree_3(BinTree* bt,BinTreeNode** node,char* str){
//    if(*str == bt->refvalue){
//        *node = NULL;
//      ++str;
//    } else {
//        *node = (BinTreeNode*) malloc(sizeof(BinTreeNode));
//        assert(node != NULL);
//        (*node)->data = *str;
//        //递归创建
//      str++
//        createBinTree_3(bt,&(*node)->leftChild,str);
//        createBinTree_3(bt,&(*node)->rightChild,str);
//    }
//}
//改进 ABC##DE##F##G#H##
void createBinTree_3(BinTree* bt,BinTreeNode** node,char** str){
    if(**str == bt->refvalue){
        ++(*str);
        *node = NULL;
    } else {
        *node = (BinTreeNode*) malloc(sizeof(BinTreeNode));
        assert(node != NULL);
        (*node)->data = **str;
        //递归创建
        ++(*str);
        createBinTree_3(bt,&(*node)->leftChild,str);

        createBinTree_3(bt,&(*node)->rightChild,str);
    }
}

3、二叉树遍历

3.1、递归方式

//先序遍历
void preOrder(BinTreeNode* node){
    if(node != NULL){
        printf("%c ",node->data);
        preOrder(node->leftChild);
        preOrder(node->rightChild);
    }
}

//中序遍历
void inOrder(BinTreeNode* node){
    if(node != NULL){
        inOrder(node->leftChild);
        printf("%c ",node->data);
        inOrder(node->rightChild);
    }
} 

//后序遍历
void postOrder(BinTreeNode* node){
    if(node != NULL){
        postOrder(node->leftChild);
        postOrder(node->rightChild);
        printf("%c ",node->data);
    }
}

3.2、非递归方式

//先序遍历-不采用递归
void preOrder(BinTreeNode* node){
    if(node != NULL){
        SeqStack st;
        InitStack(&st);
        BinTreeNode* p;
        //根节点入栈 
        push(&st,node);
        while(!isEmpty(&st)){
            //当栈不为空
            //获取栈顶 元素 
            GetTop(&st,&p);
            //出栈
            Pop(&st);
            //访问元素 
            printf("%c ",p->data); 
            if(p->rightChild != NULL)
                //先将右节点入栈 
                push(&st,p->rightChild);
            if(p->leftChild != NULL)
                //在将左节点入栈 
                push(&st,p->leftChild);
        }
    }
} 

// 中序遍历
void inOrder(BinTreeNode* node){
    if(node != NULL){
        SeqStack st;
        InitStack(&st);
        BinTreeNode* p;
        //根节点入栈 
        push(&st,node);
        while(! isEmpty(&st)){
            //将当前节点的左子树入栈 
            while(node != NULL && node->leftChild != NULL){
                Push(&st,node->leftChild);
                node = node->leftChild;
            }
            //当访问该节点的所有左子树时 
            GetTop(&st,&p);
            Pop(&st);
            printf("%c ",p->data);
            //访问完该节点的所有左子树,将该节点的右子树入栈 
            if(p->rightChild != NULL){
                node = p->rightChild;
                if(node != NULL)
                    Push(&st,node);
            }
        }
    }
} 
//后序遍历-非递归 核心思想:将该节点的左右子树都遍历完才访问该元素
//修改结构,增加标记位来记录该节点从哪边返回 
typedef enum{L,R} Tag;
typedef struct StkNode{
    BinTreeNode* prt;
    Tag tag;
}StkNode;

void postOrder(BinTreeNode* t){
    if(t != NULL){
        SeqStack st;
        InitStack(&st);
        StkNode sn;
        BinTreeNode* p;
        do{
            while(t != NULL){
                sn.prt = t;
                sn.tag = L;
                Push(&st,sn);
                t = t->leftChild;
            }
            bool flag = true;//是否继续访问的标记
            while(flag && !isEmpty(&st)){
                GetTop(&st, &sn);
                Pop(&st);
                p = sn->prt;
                switch(sn.tag){
                    case L:
                        //说明还没访问该节点的右子树
                        sn->tag = R;
                        Push(&st,sn);
                        flag = false;//第一次右节点,先找该右节点的左子树
                        t = p->rightChild;
                        break;  
                    case R:
                        //说明访问过右子树
                        printf("%c",p->data);
                        break; 
                }
            } 
        }while(!isEmpty(&st));
    }
} 

3.3、层次遍历

 
//层次遍历
void leverOrder(BinTreeNode* node){
    if(node == NULL)
        return; 
    BinTreeNode* v;
    LinkQueue queue;//声明队列
    initQueue(&queue);//初始化队列
    enQueue(&queue,node);//入队根节点
     
    while(!isEmpty(&queue)){
        //获取队头元素 
        GetHead(&queue,&v);
        //出队
        DeQueue(&queue);
        //访问数据 
        printf("%c",v->data);
        //左节点入队 
        if(v->leftChild != NULL)
            EnQueue(&queue,v->leftChild);
        //右节点入队 
        if(v->rightChild != NULL)
            EnQueue(&queue,v->rightChild);
    }
}

4、其他常用方法实现

//二叉树节点个数
int Size(BinTreeNode* node){
    if(node == NULL){
        return 0;
    }
    return Size(node->leftChild) + Size(node->rightChild) + 1;
}

//二叉树高度
int Height(BinTreeNode* node) {
    if(node == NULL)
        return 0;
    else {
        int left_height = Height(node->leftChild);
        int right_height = Height(node->rightChild);
        return (left_height > right_height ? left_height : right_height) + 1;
    }
}

//查找节点
BinTreeNode* Search(BinTreeNode* t,ElemType key) {
    if(t == NULL)
        return NULL;
    if(t->data == key)
        return t;
    BinTreeNode* p = Search(t->leftChild,key);
    if(p != NULL)
        return p;
    return Search(t->rightChild,key);
} 
//查找节点的父节点
BinTreeNode* Parent(BinTreeNode* t,BinTreeNode* p){
    if(t == NULL || p == NULL)
        return NULL;
    if(t->leftChild == p || t->rightChild == p)
        return t;
    BinTreeNode* q = Parent(t->leftChild,p);
    if(q != NULL)
        return q;
    return Parent(t->leftChild,p);
} 

//求左子树
BinTreeNode* leftChild(BinTreeNode* p){
    if(p != NULL)
        return p->leftChild;
    return NULL;
} 

//求右子树
BinTreeNode* rightChild(BinTreeNode* p){
    if(p != NULL)
        return p->rightChild;
    return NULL;
} 

//判空
int BinTreeEmpty(BinTree* bt){
    return bt->root == NULL;
} 

//拷贝
void copy(BinTreeNode** bt1,BinTreeNode* bt2){
    if (bt2 == NULL) {
        *bt1 = NULL; // 如果 bt2 为空,则设置 *bt1 为空
    } else {
        *bt1 = (BinTreeNode*)malloc(sizeof(BinTreeNode)); // 分配新节点
        assert(*bt1 != NULL); // 确保内存分配成功
        (*bt1)->data = bt2->data; // 复制数据
        copy(&(*bt1)->leftChild, bt2->leftChild); // 递归复制左子树
        copy(&(*bt1)->rightChild, bt2->rightChild); // 递归复制右子树
    }
} 
//清除树的所有节点
void BinTreeClear(BinTreeNode** t){
    if(*t != NULL){
        BinTreeClear(&(*t)->leftChild);
        BinTreeClear(&(*t)->rightChild);
        free(*t);
        *t = NULL;
    }
} 



int main(){
    //ABC##DE##F##G#H##
    BinTree myTree;
    initBinTree(&myTree,'#');
//    createBinTree_1(&myTree,&myTree.root);
//    myTree.root = createBinTree_2(&myTree);
    char* str = "ABC##DE##F##G#H##";
    createBinTree_3(&myTree,&myTree.root,&str);
    preOrder(myTree.root);
    printf("\n");
    inOrder(myTree.root);
    printf("\n");
    postOrder(myTree.root);
    printf("\n");
    printf("Size=%d\n",Size(myTree.root));
    printf("Height=%d\n",Height(myTree.root));
    
    BinTreeNode* p = Search(myTree.root,'B');
    BinTreeNode* q = Parent(myTree.root,p);
    printf("Parent=%c\n",q->data);
    
    return 0;
}

5、二叉树的恢复实现(VLR_LVR_LRV)

//根据先序序列和中序序列生成二叉树 
//root是一级指针 
void createBinTreeByVLRAndLVR(BinTreeNode** t,char* VLR,char* LVR,int n){
    if(n == 0)
        *t = NULL;
    else{
        int k = 0;
        //找到中序序列中的根节点位置 
        while(VLR[0] != LVR[k])
            k++;
        *t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        (*t)->data = LVR[k];
        //左子树递归创建 
        createBinTreeByVLRAndLVR(&(*t)->leftChild,VLR+1,LVR,k);
        //右子树递归创建
        // 先序遍历中 VLR+k+1之前的都是左子树的节点 
        createBinTreeByVLRAndLVR(&(*t)->rightChild,VLR + k + 1,LVR + k + 1,n - k - 1); 
    }
}

//根据中序序列和后序序列生成二叉树 后序先访问完左树再右树 
void createBinTreeByLVRAndLRV(BinTreeNode** t,char* LVR,char* LRV,int n){
    if(n == 0)
        *t = NULL;
    else{
        int k = 0;
        while(LRV[n - 1] != LVR[k])
            k++;
        *t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        (*t)->data = LVR[k];
        //右子树递归创建 
        //当找到中序遍历的根节点在k的位置时,说明k之前的节点都是左子树节点,
        // 因为是后序遍历,所以左子树一定先显示。故LRV+k 
        createBinTreeByLVRAndLRV(&(*t)->rightChild,LVR + k + 1,LRV + k,n - k - 1);
        //左子树递归创建 
        createBinTreeByLVRAndLRV(&(*t)->leftChild,LVR,LRV,k);
    }
}

int main(){
    //先序序列 
    char* VLR = "ABCDEFGH";
    //中序序列
    char* LVR = "CBEDFAGH";
    //后序序列
    char* LRV = "CEFDBHGA";
    
    int n = strlen(VLR);
    BinTree myTree;
    initBinTree(&myTree,'#');
//    createBinTreeByVLRAndLVR(&myTree.root,VLR,LVR,n);

    createBinTreeByLVRAndLRV(&myTree.root,LVR,LRV,n);
    preOrder(myTree.root);
    printf("\n");
    inOrder(myTree.root);
    printf("\n");
    postOrder(myTree.root);
    printf("\n");
    return 0;
}

 

 
posted @ 2024-09-29 08:39  颜欢兮  阅读(3)  评论(0编辑  收藏  举报