二叉树的相关操作

这篇博客详细介绍了二叉树的各种操作,包括递归和非递归的前序、中序、后序遍历,层次遍历,节点查找,父节点查找,删除节点,插入节点,获取第k层节点数,深拷贝二叉树以及计算树的深度。这些基本操作是理解二叉树数据结构的关键。
摘要由CSDN通过智能技术生成

二叉树的相关操作


  1. 二叉树的构造,清空操作

  2. 二叉树的遍历

    1. 递归前序遍历、中序遍历、后序遍历
    2. 非递归前序遍历、中序遍历、后序遍历
    3. 层次遍历
  3. 寻找指定二叉树结点

    1. 递归查找
    2. 非递归查找
  4. 寻找父结点

    1. 递归查找
    2. 非递归查找
  5. 删除指定节点及其左右子树

  6. 指定位置插入结点

  7. 求二叉树第k层的节点数

    1. 递归
    2. 非递归
  8. 深拷贝二叉树

  9. 求二叉树的深度

一:二叉树的构造,清空操作


/**
 * 前序递归构造二叉树
 * @param f
 * @param Tree
 * @return
 */
int CreatBinTree(BinTree*  Tree){
    char ch;
    scanf("%c",&ch);
    if (ch == ' '){
        *Tree = NULL;
    } else{
        (*Tree) = (BinTree)malloc(sizeof (BinNode));
        if (!(*Tree)){
            exit(0);
        }
        (*Tree)->data = ch;
        CreatBinTree(&(*Tree)->lchild);  //构造左子树
        CreatBinTree(&(*Tree)->rchild);  //构造右子树
    }
    return 1;
}
//清空二叉树
void ClearBiTree(BinTree *T){
    if (*T){    //如果当前结点不为空
        if (!(*T)->lchild){
            ClearBiTree((*T)->lchild);  //清空左子树
        } else if (!(*T)->rchild){
            ClearBiTree((*T)->rchild);  //清空右子树
        }
        free(*T);       //释放节点
        *T = NULL;
    }
}
```

`

二:二叉树的遍历

1、递归:

/**
 * 递归前序遍历
 * @param T
 */
void PreOrderTraverse(BinTree T){
    if (T){
        printf("%c\t",T->data);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }

}

/**
 * 中序遍历二叉树
 * @param T
 */
void InorderTraverse(BinTree T){
    if (T){
        InorderTraverse(T->lchild);
        printf("%c\t",T->data);
        InorderTraverse(T->rchild);
    }
}

/**
 * 后续遍历二叉树
 * @param T
 */
void PostOrderTraverse(BinTree T){
    if (T){
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        printf("%c\t",T->data);
    }
}

2、非递归

/**
 * 非递归前序遍历
 */
void PreOrder(BinTree T){
    //创建一个数组,用数组来模仿栈
    BinTree stack[15];
    int top = -1;   //栈顶指针
    BinTree p = T;
    while (p!=NULL || top!=-1){
        //当p不为空是将结点压入栈中
        if (p!=NULL){
            stack[++top] = p;
            printf("%c\t",p->data); //前序遍历在压入栈时候访问结点数据
            p = p->lchild;
        } else{ //当p为空,证明p的父结点没有左子树,则将p弹出访问右子树
            p = stack[top];
            top--;
            p = p->rchild;
        }
    }
}


/**
 * 非递归遍历二叉树
 * @param T
 */
void InOrder(BinTree T){
    BinTree stack[15];  //定义一个数组用来模拟栈的使用
    int top = -1;
    BinTree p = T;
    while (p!=NULL||top!=-1){
        if (p!=NULL){
            //将p结点压入栈
            stack[++top] = p;
            p = p->lchild;
        } else{
            p = stack[top--];
            printf("%c\t",p->data);
            p = p->rchild;
        }
    }
}


/**
 * 非递归后续遍历二叉树
 * @param T
 */
void PostOrder(BinTree T){
    BinTree stack[15];
    int flage[15];
    int top = -1;   //栈顶指针
    BinTree p = T;
    while (p!=NULL||top!=-1){
        if (p!=NULL){
            stack[++top] = p;
            flage[top] = 1;     //第一次访问,设个标志为1
            p = p->lchild;
        } else{
            if (flage[top] == 1){
                p = stack[top]; //获取栈顶元素,但是不取出
                flage[top] = 2; //标志这第二次访问
                p = p->rchild;  //访问右子树
            } else{ //第二次访问,证明也已经访问完了右子树,这时访问根节点
                p = stack[top--];
                printf("%c\t",p->data);
                p = NULL;   //置空,以便继续退栈,
            }
        }
    }
}

3、层次遍历

/**
 * 层次遍历二叉树
 * 层次遍历需要借助队列,先进先出,使用一个数组来模拟队列操作,循环队列
 * @param T
 */
void LevelTraverse(BinTree T){
    BinTree queue[15];
    int front = 0;
    int rear = 0;
    BinTree p = T;
    if (!T){
        return;
    } else{
        queue[rear] = p;
        rear = (rear+1)%15;
        while (rear!=front){    //当队列不为空时
            p = queue[front];
            printf("%c\t",p->data);
            front = (front+1)%15;   //元素出栈
            if (p->lchild!=NULL){
                //该结点的左孩子不为空
                queue[rear] = p->lchild;
                rear = (rear+1)%15;
            }
            if (p->rchild!=NULL){
                queue[rear] = p->rchild;
                rear = (rear+1)%15;
            }
        }
    }
}

三:寻找指定二叉树结点

1、递归查找

/**
 * 递归查找指定元素的结点
 * @param T
 * @param e
 * @return 返回当前元素的地址
 */
BinTree LocateNode(BinTree T,BinElemType e){
    BinTree p = NULL;
    if (T!=NULL){
        if (T->data == e){
            p = T;
        } else{
            if (p=LocateNode(T->lchild,e)){
                return p;
            }
            if (p=LocateNode(T->rchild,e)){
                return p;
            }
        }
    }
    return p;
}

3、非递归查找

/**
 * 非递归前序遍历查找在二叉树中给定数据的结点
 * @param T
 * @param e
 * @return
 */
BinTree  FindTreeNode(BinTree T,BinElemType e){
   //使用非递归前序遍历寻找
   BinTree stack[15];   //创建一个栈
   int top = -1;
   BinTree p = T;
    while (p!=NULL||top!=-1){
        if (p!=NULL){
            //判断是否相等
            if (p->data == e){
                return p;
            } else{
                stack[++top] = p;
                p = p->lchild;
            }
        } else{
            p = stack[top--];
            p = p->rchild;
        }
    }
    return NULL;
}

/**
 * 非递归后续遍历查找结点
 * @param e
 * @return
 */
BinTree PostFindTreeNode(BinTree T,BinElemType e){
    BinTree stack[15];
    int top = -1;
    int flage[15];
    BinTree p = T;
    while (p!=NULL||top!=-1){
        if (p!=NULL){
            stack[++top] = p;
            flage[top] = 1;
            p = p->lchild;
        } else{
            if (flage[top]!=2){
                //左子树为空,进行回退
                p = stack[top];
                flage[top] = 2;
                p = p->rchild;
            } else{
                p = stack[top--];
                if (e == p->data){
                    return p;
                } else{
                    p = NULL;
                }
            }
        }
    }
    return  NULL;
}

四:寻找父结点

1、递归查找

/**
 * 递归寻找指定节点的父结点
 * @param T 树
 * @param p 指定节点
 * @return 返回父结点地址
 */
BinNode* FatherRe(BinTree T,BinNode* p){
    BinNode* parent = NULL;
    if (T!=NULL){
        if (T->lchild == p||T->rchild == p){
            parent = T;
        } else{
            if (parent = FatherRe(T->lchild,p)){
                return parent;
            }
            if (parent = FatherRe(T->rchild,p)){
                return parent;
            }
        }
    }
    return parent;
}

2、非递归查找

/**
 * 非递归前序遍历查找给定节点的父结点
 * 相当于双指针
 * @param T
 * @param e
 * @return
 */
BinTree Parent(BinTree T,BinElemType e){
    BinTree stack[15];
    int top = -1;
    BinTree p = T;
    BinTree father;
    while (p!=NULL||top!=-1){
        if (p!=NULL){
            if (p->data == e){
                return father;
            }
            father = p;
            stack[++top] = p;
            p = p->lchild;

        } else{
            p = stack[top--];
            father = p;
            p = p->rchild;
        }
    }
    return NULL;
}

五:删除指定节点及其左右子树

/**
 * 删除结点及其左右子树
 * 寻找数据值为e的节点的父结点,令为p,待删结点为q结点,让父结点的指向为空,调用clear函数,将q所表示的子树删除。
 *
 * @param T
 * @param e
 * @return
 */
int DleteTreeNode(BinTree T,BinElemType e){
    BinTree p;
    BinTree parentTree = Parent(T,e);
    if ((parentTree->lchild)->data == e){
        p = parentTree->lchild;
        parentTree->lchild = NULL;
//        ClearBiTree(&p);
        return 1;
    } else if ((parentTree->rchild)->data == e){
        p = parentTree->rchild;
        parentTree->rchild = NULL;
//        ClearBiTree(&p);
        return 1;
    }
    return 0;
}

六:指定位置插入结点

/**
 * 在树T中的e结点之下插入一个新节点,并根据LR来决定插入的是右节点还是左节点
 * @param T     待插入的树
 * @param e     插入节点的父结点
 * @param newNode   插入的新节点
 * @param LR    判断是左节点还是右节点
 * @return      1表示插入成功,0表示插入失败
 * 思路:寻找数值为e的数据,并根据LR来决定插入的是做还是右子树,并用一个指针p来表示当前值为e的左或右节点,
 * 然后执行插入
 */
int InsertNode(BinTree T,BinElemType e,BinNode* newNode,char LR){
    BinTree parent = LocateNode(T,e);
    if (T==NULL||parent==NULL){
        return 0;
    }
    BinTree p = NULL;
    if (LR=='L'){
        p = parent->lchild;
        parent->lchild = newNode;
        newNode->lchild = p;
    } else if ('R'){
        p = parent->rchild;
        parent->rchild = newNode;
        newNode->rchild = p;
    }
    return 1;
}

七:求二叉树第k层的节点数

1、递归

/**
 * 递归求第k层的节点数
 * @param T
 * @param kLevel
 * @return
 */
int GetKLevelNum(BinTree T,int kLevel){
    if(T==NULL||kLevel<=0){
        return 0;
    }
    if (T!=NULL&&kLevel == 1){
        return 1;
    }
    return (GetKLevelNum(T->lchild,kLevel-1) + GetKLevelNum(T->rchild,kLevel-1));
}

2、非递归

kong

八:深拷贝二叉树

/**复制二叉树
//递归后续遍历递归复制二叉树
*/
 BinTree CopyTreePre(BinTree T){
    if (T==NULL){
        return NULL;
    }
    BinTree lchild = CopyTreePre(T->lchild);
    BinTree rchild = CopyTreePre(T->rchild);

    //创建一个根节点
    BinTree newNode = malloc(sizeof (BinNode));
    newNode ->data = T->data;
    newNode ->lchild = lchild;
    newNode->rchild = rchild;
    return newNode;
}

九:求二叉树的深度

/**
 * 求树的深度
 * @param T
 * @return
 */
int BiTreeDepth(BinTree T){
    int LD,RD;  //计算左右子树的深度
    if (T == NULL){
        return 0;
    }
    LD =BiTreeDepth(T->lchild);
    RD = BiTreeDepth(T->rchild);
    return (LD>=RD?LD:RD)+1;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值