浅入树与二叉树

1.初识树  

  首先来看树的几个很重要的概念。节点的度是这个节点所拥有的子树的个数,如果度为0那这个节点称为叶子节点。树的深度是树中所有节点的最大层数,树的度是各节点度的最大值。如果树的各节点的左右子树从左到右是有序的则为有序树,反之为无序树。树的遍历分为前序、中序和后序,树也有很多类型,下面是一些常见的树类型。

二叉树:二叉树的每个节点的子节点不会超过2个,而且它是一颗有序树,左右子树不能交换,若交换左右子树将变为另一颗不同的树。

满二叉树:在二叉树中,如果所有非叶子节点都有2个子节点,而且所有叶子节点都在同一层上(即所有叶子节点到根节点的路径相同)则是一颗满二叉树。它的节点的度只有0和2。

完全二叉树:可以将它看成是把满二叉树从右向左从下往上减去叶子节点。它的特点是所有叶子节点只能在最下层或次下层,且最下层的叶子节点都在左边。深度为n的完全二叉树在n-1层一定是满二叉树。

二叉排序树:也称为二叉查找树,特点是左子树的所有节点均小于根节点,右子树的所有节点均小于根节点且一个节点的左子树与右子树均为二叉排序树,因此二叉排序树中没有相等的树。

红黑树:它的数据结构是值、左孩子节点、右孩子节点、颜色和父节点。它不为空时,所有节点为红或黑颜色的节点且根节点是黑色,所有为null的节点为叶子节点且颜色为黑色,所有红节点的子节点都为黑色,从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。

平衡二叉树:它是在二叉排序树的基础上增加了一个特点,它的左右子树的高度之差不能超过1,如果由于插入或删除打破了这个规则则需要进行旋转恢复平衡。

2.二叉树的性质

  二叉树有如下一些主要的性质。一颗二叉树第i层最多有2^(i-1)个节点;一颗深度为k的二叉树中,最多有2^k-1个节点;对于一颗非空的二叉树,如果叶子节点为数为n0,度为2的节点树为n2,则有k=j+1。设这颗二叉树的 总节点为n,它等于子节点分别为0、1、2的总和,这样可以得到一个等式n=n1+n2+n3。接下来要利用二叉树中的分支,假设分支数为m,除了根节点没有父节点外其余所有节点都有父节点也就是有“分支”,对于有2个子节点的节点,每一个这样的节点表示有2个分支,同理一个子节点的节点代表的是有一个分支。这样可以得到另两个等式m=n-1,m=n1+2n2。通过这两个等式可以得到n0=n2+1;

  一颗有n个节点的完全二叉树深度为k,则k为lbn+1,由完全二叉树的定义可知深度为k的节点数范围是2^(k-1)<=n<2^k-1,对该不等式取对数可得到lbn<k<=lbn+1,故k为lbn+1。如果对具有n个节点的完全二叉树按照从左到右从上到下的顺序进行编号,对于其中任意一个序号为k的节点,它不为1时父节点的序号为k/2。如果2k<=n,则它的左孩子节点序号为2k,如果2k>n则该节点为左孩子节点。如果2k+1<=n,则右孩子节点为2k+1,而2k+1>n时则该节点无右孩子节点。

3.二叉树的遍历

struct BinaryTree{
    int value;
    BinaryTree* leftTree;
    BinaryTree* rightTree;
};
//前序遍历
void FrontTraverse(BinaryTree* root)
{
    if(root!=NULL)
    {
        if(root->leftTree)
            FrontTraverse(root->leftTree);
        printf("%d ",root->value);
        if(root->rightTree)
            FrontTraverse(root->rightTree);
    }
}
//中序遍历
void MiddleTraverse(BinaryTree* root)
{
    if(root!=NULL)
    {
        printf("%d ",root->value);
        if(root->leftTree)
            FrontTraverse(root->leftTree);
        if(root->rightTree)
            FrontTraverse(root->rightTree);
    }
}
//后序遍历
void BehindTraverse(BinaryTree* root)
{
    if(root!=NULL)
    {
        if(root->leftTree)
            FrontTraverse(root->leftTree);
        if(root->rightTree)
            FrontTraverse(root->rightTree);
        printf("%d ",root->value);
    }
}

4.二叉树的基本操作

#include<stdio.h>
#include<stdlib.h>
struct BinaryTree{
    int value;
    BinaryTree* leftTree;
    BinaryTree* rightTree;
    BinaryTree()
    {
        leftTree=NULL;
        rightTree=NULL;
    }
};
//初始化二叉树
void InitBiTree(BinaryTree* root)
{
    BinaryTree* node1=new BinaryTree();
    BinaryTree* node2=new BinaryTree();
    BinaryTree* node3=new BinaryTree();
    BinaryTree* node4=new BinaryTree();
    BinaryTree* node5=new BinaryTree();
    node1->value=4;
    node2->value=12;
    node3->value=5;
    node4->value=10;
    node5->value=15;
    root->leftTree=node1;
    root->rightTree=node2;
    node1->rightTree=node3;
    node2->leftTree=node4;
    node2->rightTree=node5;
}

//中序遍历
void MiddleTraverse(BinaryTree* root)
{
    if(root==NULL)
        return;
    if(root->leftTree)
        MiddleTraverse(root->leftTree);
    printf("%d ",root->value);
    if(root->rightTree)
        MiddleTraverse(root->rightTree);
}

//新增二叉树的节点
void AddBiTree(BinaryTree* root,int key)
{
    if(root==NULL)
        return;
    BinaryTree* keyNode=new BinaryTree();
    keyNode->value=key;
    BinaryTree* node=root;
    BinaryTree* prevNode;
    if(key>node->value)
    {
        while(node&&node->value<key)
        {
            prevNode=node;
            node=node->rightTree;
        }
        if(node==NULL)                //node节点此时有可能是NULL
            prevNode->rightTree=keyNode;
        else
        {
            //现在node的value是比key大的
            prevNode->rightTree=keyNode;
            keyNode->rightTree=node;
        }
    }
    else
    {
        while(node&&node->value>key)
        {
            prevNode=node;
            node=node->leftTree;
        }
        if(node==NULL)                //node节点此时有可能是NULL
            prevNode->leftTree=keyNode;
        else
        {
            //现在node的value是比key小的
            prevNode->leftTree=keyNode;
            keyNode->leftTree=node;
        }
    }
}
//查找一个节点,得到这个节点的引用以及父节点
void QueryBiTree(BinaryTree *root,int key,BinaryTree **keyNode,BinaryTree **parentNode)
{
    if(root==NULL)
        return;
    if(root->value==key)
    {
        *keyNode=root;
        return;
    }
    BinaryTree* node=root;
    if(root->leftTree&&root->leftTree->value==key)
    {
            *keyNode=root->leftTree;
            *parentNode=root;
            return;
    }
    if(root->rightTree && root->rightTree->value==key)
    {
            *keyNode=root->rightTree;
            *parentNode=root;
            return;
    }
    if(root->value>key)
        QueryBiTree(root->leftTree,key,keyNode,parentNode);
    if(root->value<key)
        QueryBiTree(root->rightTree,key,keyNode,parentNode);
}
//删除一个节点
void DeleteBiTree(BinaryTree* root,int key)
{
    if(root==NULL)
        return;
    //首先找到这个节点
    bool isLeft=false;
    BinaryTree* keyNode=NULL;
    BinaryTree* parentNode=NULL;
    QueryBiTree(root,key,&keyNode,&parentNode);
    if(parentNode&&parentNode->leftTree==keyNode)
        isLeft=true;
    //1.如果该节点有右子树,寻找右子树的最左节点,这个节点也可能是根节点。
    if(keyNode->rightTree)
    {
        BinaryTree* leftNode=keyNode->rightTree;
        //如果被删除节点的右孩子节点的左节点为空
        if(leftNode->leftTree==NULL)
        {
            //将右孩子节点的值赋给keyNode并删除keyNode->rightNode;
            keyNode->value=keyNode->rightTree->value;
            keyNode->rightTree=keyNode->rightTree->rightTree;
        }
        else
        {
            BinaryTree* parentLeftNode;
            //不停的寻找右子树的最左节点
            while(leftNode->leftTree)
            {
                //leftNode的父节点
                parentLeftNode=leftNode;
                leftNode=leftNode->leftTree;
            }
            //此时leftNode则是右子树里的最左节点,然后将这个节点的值赋给keyNode
            keyNode->value=leftNode->value;
            parentLeftNode->leftTree=leftNode->rightTree;
        }
        delete leftNode;
        return;
    }
    //2.如果该节点只有左子树,这里要分情况讨论,因为要删除的节点有可能是根节点
    if(keyNode->leftTree&&keyNode->rightTree==NULL)
    {
        //如果此时删除的节点是根节点
        if(parentNode==NULL)
            root=root->leftTree;
        else
        {
            //如果被删除节点的右子树为空,则直接去掉这个节点
            if(isLeft)
                parentNode->leftTree=keyNode->leftTree;
            else
                parentNode->rightTree=keyNode->leftTree;
            delete keyNode;
        }
        return;
    }
    //3.如果该节点本身是叶子节点
    if(keyNode->leftTree==NULL&&keyNode->rightTree==NULL)
    {
        //如果此时节点是根节点
        if(keyNode==root)
            root=NULL;
        else
        {
            if(isLeft)
                parentNode->leftTree=NULL;
            else
                parentNode->leftTree=NULL;
        }
        delete keyNode;
    }
}

void main()
{
    BinaryTree* root=new BinaryTree();
    root->value=6;
    //初始化二叉树
    InitBiTree(root);

    //新增节点9,5
    AddBiTree(root,3);
    MiddleTraverse(root);
    printf("\n");
    AddBiTree(root,9);
    MiddleTraverse(root);
    printf("\n");

    //删除节点
    //DeleteBiTree(root,3);
    //DeleteBiTree(root,4);
    //DeleteBiTree(root,5);
    //DeleteBiTree(root,6);
    //DeleteBiTree(root,9);
    DeleteBiTree(root,12);
    MiddleTraverse(root);
    printf("\n");
}

  这是我自己写的关于二叉树的创建、新增、查找与删除的代码,如有错误还请各位员友指出!

时间: 2024-10-10 07:26:48

浅入树与二叉树的相关文章

浅谈数据结构-二叉树

浅谈数据结构-二叉树 二叉树是树的特殊一种,具有如下特点:1.每个结点最多有两颗子树,结点的度最大为2.2.左子树和右子树是有顺序的,次序不能颠倒.3.即使某结点只有一个子树,也要区分左右子树. 一.特殊的二叉树及特点 1.斜树 所有的结点都只有左子树(左斜树),或者只有右子树(右斜树).这就是斜树,应用较少 2.满二叉树 所有的分支结点都存在左子树和右子树,并且所有的叶子结点都在同一层上,这样就是满二叉树.就是完美圆满的意思,关键在于树的平衡. 根据满二叉树的定义,得到其特点为: 叶子只能出现

数据结构6.2_二叉树

1.二叉树的定义: 二叉树(Binary True)是另一种树型结构,它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点),并且,二叉树的子树有左右之分,其次序不能任意颠倒. 以下是二叉树的五种基本形态: 2.二叉树的性质: 二叉树的结构特点和性质:https://blog.csdn.net/qq_34322188/article/details/82346068 二叉树的性质有三条: 1)性质1:在二叉树的第i层上至多有2^(i-1)个结点(i>=1):  //利用归纳法可以证

20172302 《Java软件结构与数据结构》第六周学习总结

2018年学习总结博客总目录:第一周 第二周 第三周 第四周 第五周 第六周 教材学习内容总结 1.树的概述及基本概念 (1)树是一种非线性数据结构,其中的元素被组织成了一个层次结构. (2)树由一个包含结点和边的集构成,其中元素被存储在这些结点中,边则将一个结点和另一个结点连接起来.每一结点都位于该树层次结构中的某一特顶层上. (3)树的根式位于该树顶层的唯一结点.一棵树只有一个根结点. (4)位于树中较底层的结点是上一层的孩子.一个结点只有一个双亲,但一个结点可以有很多孩子.同一双亲的两个结

浅谈数据结构之二叉树存储结构实现(七)

树:是n个结点的有限集:n=0时称为空树.在任意一棵非空树中,有且只有一个特定的结点称为根结点:其余的结点可分为m(m>0)个互不相交的有限集,其中每一个有限集都是一棵子树.结点拥有的子树数称为结点的度:度为0的结点称为叶结点或者终端结点,度不为0的结点称为分支结点或者非终端结点:树的度就是树内各结点的度的最大值. 二叉树的特点有:(1).每个结点最多有两棵子树,所以二叉树不存在度大于2的结点(注意:不是只有两棵子树,而是最多有两棵子树,没有子树或者有一颗子树都是可以的);(2).左子树和右子树

浅谈二叉树遍历的栈方法

  众多周知,对于二叉树的遍历, 一种比较容易理解以及编写的方式就是递归的方式了,下面针对二叉树遍历的中序遍历做一个简单的分析: void travelTree(BiTree T, int deep){ if (T->lchild != NULL) travelTree(T->lchild, ++deep); for (int x = 0; x < deep; x++) { printf("--"); } printf("%c\n", T->

浅谈数据结构-树和二叉树之间关系

树都可用二叉链表作为存储结构,对比各自的结点结构可以看出,以二叉链表作为媒介可以导出树和二叉树之间的一个对应关系. ◆ 从物理结构来看,树和二叉树的二叉链表是相同的,只是对指针的逻辑解释不同而已. ◆ 从树的二叉链表表示的定义可知,任何一棵和树对应的二叉树,其右子树一定为空. 1 树转换成二叉树 对于一般的树,可以方便地转换成一棵唯一的二叉树与之对应.将树转换成二叉树在"孩子兄弟表示法"中已给出,其详细步骤是: ⑴ 加虚线.在所有兄弟结点之间加线. ⑵ 去连线.只保留大孩子(除最左的第

浅谈数和二叉树

树:非线性结构.一对多的关系. 根节点:没有前驱节点的节点. 叶子节点:没有后继节点的节点. 节点的度:一个节点的子节点个数. 树的度:树中度最大的节点的度. 树的节点个数计算: 满树:一棵度为n,高度为h的满树,其节点个数是: n^0 + n^1 + n^2 + .......+ n^(n-1)  等比公式 总结点树和叶子节点数的计算: 度 个数 1 n1 2 n2 ...   ... d    nd n总 = n1 + 2n2  + 3n3 +.... +d*nd -1 n0 = n总 -

浅谈二叉树

二叉树 二叉树不是树的一种特殊情形,尽管其与树有许多相似之处,但树和二叉树有两个主要差别: 1. 树中结点的最大度数没有限制,而二叉树结点的最大度数为2: 2. 树的结点无左.右之分,而二叉树的结点只有左.右之分. 下图即为一个典型是二叉树!!! 接下来就来分析这个图: 在这“棵”树上 根结点 ------ F 叶子结点 ------ A .B .H . M 子结点 ----- 除了 根结点F 的其他结点 父亲结点 ----- 除了 叶子结点 的其他结点 兄弟结点 ----- [C .E][A

浅谈二叉树的遍历(先序遍历、中序遍历、后序遍历)

先序遍历:根-左儿子-右儿子(根左右) 中序遍历:左儿子-根-右儿子(左根右) 后序遍历:左儿子-右儿子-根(左右根) 通常来说这都记得住. 这时MY大神来一句:"我记不住" 记不住的话可以这么理解:先序遍历根在先,中序遍历根在中,后序遍历根在后,左儿子永大于右儿子 现在来看一张图 这张图的遍历: 中序遍历:4251637 4,2,5--左根右嘛这可以理解,可是后面为什么是1? 我们把425看做一个整体,再把637看做一个整体.425是1的左儿子(左子树),637就是1的右儿子.是哈.