二叉树的一系列操作

//二叉树学习过程中的问题和代码集合//按先序序列创建二叉树//树的高度//求树的结点数//求二叉树第K层的节点个数//求二叉树中叶子节点的个数//求二叉树中节点的最大距离//两结点最低公共祖先//判断二叉树是不是平衡二叉树//释放树空间

//感谢:http://blog.csdn.net/luckyxiaoqiang/article/details/7518888#topic1

#include<iostream>
#include<stack>
#include<queue>
using namespace std;

//二叉树结点
typedef int DateType;
typedef struct BiTNode{
    DateType data;
    struct BiTNode *lchild,*rchild,*m_pLeft,*m_pRight;
}BiTNode,*BiTree;

//按先序序列创建二叉树
int CreateBiTree(BiTree &T){

    char data;
    //‘#’表示空树
    cin>>data;
    if(data == ‘#‘){
        T = NULL;
    }
    else{
        T = (BiTree)malloc(sizeof(BiTNode));

        T->data = data;

        CreateBiTree(T->lchild);

        CreateBiTree(T->rchild);
    }
    return 0;
}
//输出
void Visit(BiTree T){
    if(T->data != ‘#‘){
        printf("%c ",T->data);
    }
}

//先序遍历
void PreOrder(BiTree T){
    if(T != NULL){
        //访问根节点
        Visit(T);
        //访问左子结点
        PreOrder(T->lchild);
        //访问右子结点
        PreOrder(T->rchild);
    }
}
//中序遍历
void InOrder(BiTree T){
    if(T != NULL){
        //访问左子结点
        InOrder(T->lchild);
        //访问根节点
        Visit(T);
        //访问右子结点
        InOrder(T->rchild);
    }
}
//后序遍历
void PostOrder(BiTree T){
    if(T != NULL){
        //访问左子结点
        PostOrder(T->lchild);
        //访问右子结点
        PostOrder(T->rchild);
        //访问根节点
        Visit(T);
    }
}

//树的高度
//Depth(t)= max( Depth(lchild),Depth(rchild) ) + 1
int BinTreeDepth(BiTree t)
{
    int h,h1,h2;
    if(t == NULL)    return 0;
    else
    {
        h1 = BinTreeDepth(t->lchild);
        h2 = BinTreeDepth(t->rchild);
        h = max(h1,h2) + 1;
        return h;
    }

}

//求树的结点数
//树的结点数=左子树 + 右子树 + 1;
int getNodeNum(BiTree t)
{
    if(t == NULL) return 0;
    return (getNodeNum(t->lchild)+getNodeNum(t->rchild)+1);
}

//求二叉树第K层的节点个数
//NodeNum(t,k) = NodeNum(t->lchild,k-1)+NodeNum(t->rchild,k-1)
int GetNodeNumKthLevel(BiTree t, int k)
{
    if(t == NULL || k < 1)
        return 0;
    if(k == 1)
        return 1;
    // 左子树中k-1层的节点个数
    int numLeft = GetNodeNumKthLevel(t->lchild, k-1);
    // 右子树中k-1层的节点个数
    int numRight = GetNodeNumKthLevel(t->rchild, k-1);
    return (numLeft + numRight);
}

//求二叉树中叶子节点的个数
//左右儿子为NULL
//则:LeafNum(t) = LeafNum(t->lchild) + LeafNum(t->rchild);
int GetLeafNodeNum(BiTree t)
{
    if(t == NULL)
        return 0;
    if(t->lchild ==NULL && t->rchild ==NULL)
        return 1;
    int numleft = GetLeafNodeNum(t->lchild);
    int numright = GetLeafNodeNum(t->rchild);

    return (numleft + numright);
}

//求二叉树中节点的最大距离
//MaxDistance(t->lchild)//MacDistance(t->rchild)
//MaxLeft(t->lchild)+MaxRight(t->rchild)
int GetMaxDistance(BiTree t, int & maxLeft, int & maxRight)
{
    // maxLeft, 左子树中的节点距离根节点的最远距离
    // maxRight, 右子树中的节点距离根节点的最远距离
    if(t == NULL)
    {
        maxLeft = 0;
        maxRight = 0;
        return 0;
    }
    int maxLL, maxLR, maxRL, maxRR;
    int maxDistLeft, maxDistRight;
    if(t->lchild != NULL)
    {
        maxDistLeft = GetMaxDistance(t->lchild, maxLL, maxLR);
        maxLeft = max(maxLL, maxLR) + 1;
    }
    else
    {
        maxDistLeft = 0;
        maxLeft = 0;
    }
    if(t->rchild != NULL)
    {
        maxDistRight = GetMaxDistance(t->rchild, maxRL, maxRR);
        maxRight = max(maxRL, maxRR) + 1;
    }
    else
    {
        maxDistRight = 0;
        maxRight = 0;
    }
    return max(max(maxDistLeft, maxDistRight), maxLeft+maxRight);
}

//两结点最低公共祖先
//如果两个节点分别在根节点的左子树和右子树,则返回根节点
//如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树
//求最近公共祖先:
/*
//应该就是这样的啊,为什么运行的时候出现内存访问冲突的问题........
bool FindNode(BiTree t, DateType x)
{
    if(t == NULL || x == NULL)
        return false;
    if(t->data == x)
        return true;
    bool found = FindNode(t->lchild, x);
    if(!found)
        found = FindNode(t->rchild, x);
    return found;
}

DateType  GetLastCommonParent(BiTree t ,DateType A,DateType B)
{
    if(FindNode(t->lchild,A))
    {
        if(FindNode(t->rchild,B))
            return t->data;
        else
            return GetLastCommonParent(t->lchild,A,B);
    }
    else
    {
        if(FindNode(t->lchild,B))
            return t->data;
        else
            return GetLastCommonParent(t->rchild,A,B);
    }
}
*/

//判断二叉树是不是平衡二叉树
//如果左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,返回真,其他返回假
bool isAVL(BiTree t, int & height)
{
    if(t == NULL) // 空树,返回真
    {
        height = 0;
        return true;
    }
    int heightLeft;
    bool resultLeft = isAVL(t->lchild, heightLeft);
    int heightRight;
    bool resultRight = isAVL(t->rchild, heightRight);
    // 左子树和右子树都是AVL,并且高度相差不大于1,返回真
    if(resultLeft && resultRight && abs(heightLeft - heightRight) <= 1)
    {
        height = max(heightLeft, heightRight) + 1;
        return true;
    }
    else
    {
        height = max(heightLeft, heightRight) + 1;
        return false;
    }
}

//释放树空间
void DestroyBinTree(BiTree t)
{
    if(t==NULL) return;
    DestroyBinTree(t->lchild);
    DestroyBinTree(t->rchild);
    t->lchild=NULL;
    t->rchild=NULL;
    free(t);
}

//先序遍历(非递归)
//思路:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,//出栈,再先序遍历T的右子树。

void PreOrder2(BiTree T){
    stack<BiTree> stack;
    //p是遍历指针
    BiTree p = T;
    //栈不空或者p不空时循环
    while(p || !stack.empty()){
        if(p != NULL){
            //存入栈中
            stack.push(p);
            //访问根节点
            printf("%c ",p->data);
            //遍历左子树
            p = p->lchild;
        }
        else{
            //退栈
            p = stack.top();
            stack.pop();
            //访问右子树
            p = p->rchild;
        }
    }//while
}
//中序遍历(非递归)
//思路:T是要遍历树的根指针,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。//先将T入栈,遍历左子树;
//遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。

void InOrder2(BiTree T){
    stack<BiTree> stack;
    //p是遍历指针
    BiTree p = T;
    //栈不空或者p不空时循环
    while(p || !stack.empty()){
        if(p != NULL){
            //存入栈中
            stack.push(p);
            //遍历左子树
            p = p->lchild;
        }
        else{
            //退栈,访问根节点
            p = stack.top();
            printf("%c ",p->data);
            stack.pop();
            //访问右子树
            p = p->rchild;
        }
    }//while
}

//后序遍历(非递归)
typedef struct BiTNodePost{
    BiTree biTree;
    char tag;
}BiTNodePost,*BiTreePost;
//后序遍历
void PostOrder2(BiTree T){
    stack<BiTreePost> stack;
    //p是遍历指针
    BiTree p = T;
    BiTreePost BT;
    //栈不空或者p不空时循环
    while(p != NULL || !stack.empty()){
        //遍历左子树
        while(p != NULL){
            BT = (BiTreePost)malloc(sizeof(BiTNodePost));
            BT->biTree = p;
            //访问过左子树
            BT->tag = ‘L‘;
            stack.push(BT);
            p = p->lchild;
        }
        //左右子树访问完毕访问根节点
        while(!stack.empty() && (stack.top())->tag == ‘R‘){
            BT = stack.top();
            //退栈
            stack.pop();
            BT->biTree;
            printf("%c ",BT->biTree->data);
        }
        //遍历右子树
        if(!stack.empty()){
            BT = stack.top();
            //访问过右子树
            BT->tag = ‘R‘;
            p = BT->biTree;
            p = p->rchild;
        }
    }//while
}
//层次遍历
void LevelOrder(BiTree T){
    BiTree p = T;
    //队列
    queue<BiTree> queue;
    //根节点入队
    queue.push(p);
    //队列不空循环
    while(!queue.empty()){
        //对头元素出队
        p = queue.front();
        //访问p指向的结点
        printf("%c ",p->data);
        //退出队列
        queue.pop();
        //左子树不空,将左子树入队
        if(p->lchild != NULL){
            queue.push(p->lchild);
        }
        //右子树不空,将右子树入队
        if(p->rchild != NULL){
            queue.push(p->rchild);
        }
    }
}
int main()
{

    //测试:ABC##DE#G##F###
    //测试:124##57##8##3#6##
    BiTree T;
    cout<<"先序输入二叉树"<<endl;
    CreateBiTree(T);

    printf("先序遍历:\n");
    PreOrder(T);
    printf("\n");

    printf("先序遍历(非递归):\n");
    PreOrder2(T);
    printf("\n");

    printf("中序遍历:\n");
    InOrder(T);
    printf("\n");

    printf("中序遍历(非递归):\n");
    InOrder2(T);
    printf("\n");

    printf("后序遍历:\n");
    PostOrder(T);
    printf("\n");

    printf("后序遍历(非递归):\n");
    PostOrder2(T);
    printf("\n");

    printf("层次遍历:\n");
    LevelOrder(T);
    printf("\n");

    cout<<endl<<"树的高度为:"<<BinTreeDepth(T)<<endl<<endl;

    cout<<"结点数"<<getNodeNum(T)<<endl<<endl;

    cout<<"二叉树第K层的节点个数"<<endl;
    int k;    cin>>k;
    cout<<"二叉树第K层的节点个数"<<endl;   cout<<GetNodeNumKthLevel(T,k)<<endl<<endl;

    cout<<"二叉树中叶子节点的个数"<<endl<<GetLeafNodeNum(T)<<endl<<endl;

    int maxLeft = 0;
    int maxRight = 0;
    cout<<"二叉树中节点的最大距离"<<endl;  cout<<<<GetMaxDistance(T, maxLeft, maxRight)<<endl<<endl;

    //cout<<"两结点最低公共祖先"<<endl;
    //DateType A,B;
    ///cin>>A>>B;
    //cout<<GetLastCommonParent(T,A,B)<<endl;

    int height = 0;
    cout<<"判断二叉树是不是平衡二叉树"<<endl<<isAVL(T,height)<<endl<<endl;

    cout <<"释放树空间"<<endl<<endl;
    DestroyBinTree(T);

    system("pause");
    return 0;
}

总结:

二叉树的操作主要是用递归,只要用递归的思想就很容易解决问题,可是递归的效率不高,所以在遍历的时候要想想不用递归该怎么做?

接下来:

用分层的方法来创建二叉树

访问内存出错的问题,指针

线索二叉树、搜索二叉树。

时间: 2024-10-12 16:17:39

二叉树的一系列操作的相关文章

二叉树的相关操作

#include<stdio.h> #include<malloc.h> #define MAXSIZE 20 typedef char TEelemtype; typedef struct BiTNode{ TEelemtype data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; //队列的方式 typedef struct queueelem { BiTNode* b[MAXSIZE]; int front,rear;

二叉树各种相关操作(建立二叉树、前序、中序、后序、求二叉树的深度、查找二叉树节点,层次遍历二叉树等)(C语言版)

将二叉树相关的操作集中在一个实例里,有助于理解有关二叉树的相关操作: 1.定义树的结构体: 1 typedef struct TreeNode{ 2 int data; 3 struct TreeNode *left; 4 struct TreeNode *right; 5 }TreeNode; 2.创建根节点: 1 TreeNode *creatRoot(){ 2 TreeNode * root =(TreeNode *)malloc(sizeof(TreeNode)); 3 if(NULL=

微信公众账户模拟登陆后的一系列操作

<?php header("content-type:text/html;charset=utf-8"); /** * wx_mass * * 完成微信公众账户模拟登陆后的一系列操作 * mass($content) 调用微信群发接口,群发文本信息 * getUserList($page,$pagesize,$group) 获取用户信息 * * 群发demo * * $user=array('account'=>'公众账户名称','password'=>'密码');

java实现二叉树的常见操作

本文转自:红客联盟 解释:程序调用自身的编程技巧叫做递归. 程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量.递归的能力在于用有限的语句来定义对象的无限集合. 递归的三个条件: 边界条件 递归前进段 递归返回段 当边界条件不

二叉树的简单操作

#define _CRT_SECURE_NO_WARNINGS #define m 100 typedef char DataType; typedef struct Node /*二叉链表的结构体*/ { DataType data; struct Node * LChild; struct Node * RChild; }BiTNode, *BiTree; #define Queue_Size 100 typedef BiTree QueueElement; typedef struct /

数据结构开发(24):二叉树中属性操作、层次遍历与典型遍历

0.目录 1.二叉树中属性操作的实现 2.二叉树结构的层次遍历 3.二叉树的典型遍历方式 4.小结 1.二叉树中属性操作的实现 二叉树的属性操作: 二叉树中结点的数目: 定义功能:count(node) 在 node 为根结点的二叉树中统计结点数目 在BTree.h中实现统计结点数目: protected: int count(BTreeNode<T>* node) const { int ret = 0; if( node != NULL ) { ret = count(node->l

数据结构开发(25):二叉树中属性操作、层次遍历与典型遍历

0.目录 1.二叉树的比较与相加 2.二叉树的线索化实现 3.二叉树的经典面试题分析 3.1 单度结点删除 3.2 中序线索化二叉树 4.小结 1.二叉树的比较与相加 二叉树的克隆操作: SharedPointer< BTree<T> > clone() const 克隆当前树的一份拷贝 返回值为堆空间中的一棵新二叉树 ( 与当前树相等 ) 二叉树的克隆: 定义功能:clone(node) 拷贝 node 为根结点的二叉树 ( 数据元素在对应位置相等 ) 在BTree.h中实现二叉

事务隔离 保证一系列操作的完整性

3 事务隔离 保证一系列操作的完整性 在mysql中什么是事务? ????举例说明:转账行为 ????????????你要给朋友转100块钱,而此时你的银行卡只有100块钱. ? 转账过程具体到程序里会有一系列的操作,比如查询余额.做加减法.更新余额等,这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,你这100块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就乱了么?这时就要用到"事务"这个概念了. ? 事务定义: 事务就是要保证一组数据

二叉树的其他操作

之前实现过二叉树的创建,非递归遍历和递归遍历.现在添加一些其他的操作,包括: 销毁一棵树 计算树的深度(高度) .计算叶子节点的个数 计算所有节点的个数 复制二叉树 具体见代码: #include <stdio.h> #include <stdlib.h> typedef struct Node {     int data;     struct Node* lchild;     struct Node* rchild; }Node; //创建树 Node* create_tr