二叉树

本文详细介绍了二叉树的基础概念,包括节点、父节点、子节点和兄弟节点,以及树的深度和节点的度。接着阐述了二叉树的特点,如左子节点<父节点<右子节点,并讨论了不同类型的二叉树形状,如斜树、满二叉树和完全二叉树。此外,还探讨了二叉树的常见操作,如建立、遍历(前序、中序、后序和层序遍历)、搜索和删除节点,以及平衡二叉树的重要性。
摘要由CSDN通过智能技术生成

二叉树是一种特殊的树形结构,这篇博文主要介绍二叉树的特点和二叉树的操作。

介绍二叉树

基础概念

节点

节点是一个结构体,在二叉树中节点专指树节点,树节点在C中的一般定义形式为

struct Node{
   
    struct Node *left;
	int value;
	struct Node *right;
	};

根据代码,我们可以看见一个节点主要由三部分组成:左分支序号右分支。除这些外,可以自由加入储存信息的内容,但这三个部分是必要的。形象地说,节点就像是一个伸出两个分支的树枝,多个这样的节点一起构成一个树。

父节点、子节点和兄弟节点

节点间的关系
父节点与子节点对应,直白地说,相互连接的两个节点,在上面的节点称为在下面的节点的父节点,在下面的节点称为在上面的节点的子节点。

兄弟节点,直白地说就是有同一个父节点的多个节点。

以上图为例,C的子节点有E和F,D的子节点有G、H和I,B和C为兄弟节点。

  • 一个父节点可以有多个子节点
  • 一个子节点只能有一个父节点
  • 一个节点可以既为父节点,又为子节点

树的深度和节点的度

树是一种由上至下分层,每层的节点数呈指数增加的结构,一个树的层数就是树的深度。

以下图为例,我们可以说树的深度为4。
树的深度

一个节点有几个子节点成为这个节点的度。以上图为例,A的度为2,E的度为1,D的度为3。对于二叉树而言,节点的度只能为0、1、2。

认识二叉树

二叉树的特点

  • 对于一个二叉树父节点的子节点,左侧的子节点称为左子节点,右侧的子节点称为右子节点。
  • 左子节点<父节点<右子节点。
  • 即使一个父节点只有一个子节点或没有子节点,子节点依然有左右之分。
  • 以左子节点为根节点的子树为左子树,以右子节点为根节点的子树为右子树。

二叉树的形状

二叉树1
这是最普通的二叉树,符合二叉树的所有定义,但没有特殊的性质。
二叉树2
二叉树3
上面的两个树称为斜树,对于二叉树搜索,斜树是最费时的结构,因此需要对斜树进行平衡,这在后面的博文中会有介绍。
二叉树4
这是满二叉树,是最理想的二叉树结构。在满二叉树中,叶节点(无子节点的节点)只出现在最下面一层并且最下面一层全是叶节点。每个父节点的度都为2。
二叉树5
这是完全二叉树,如果对一棵树的节点按层、自左至右进行编号i(1<=i<=n),每一个节点都与同样深度的满二叉树对应,则称这个树为完全二叉树。完全二叉树有许多性质。

  • 叶节点只出现在最下层和次下层
  • 最下层叶节点集中在左侧
  • 次下层叶节点集中在右侧
  • 左子树与右子树的深度差<=1
  • 如果节点度为1,则节点只有左子节点,没有右子节点

二叉树的操作

建立二叉树

对于节点的序号,我们规定在二叉树中的所有节点满足左子节点<父节点<右子节点,因此,若我们想要插入一个新的节点,就需要根据这个特点找到新的节点应该在的位置,并连接新插入的节点和它的父节点。

struct Node *planttree()
{
   
    int v;
    struct Node *pre,*current,*p,*root;
    printf("we will define the root,please give me a number\n");
    scanf("%d",&v);
    root=(struct Node *)malloc(sizeof(struct Node)); /*建立根节点*/
    (*root).left=NULL;
    (*root).value=v;
    (*root).right=NULL;
    printf("please add a number\n");
    scanf("%d",&v);
    while(v)                                                              /*只要v不为负数,就继续插入节点,结束插入的条件可以更改*/
    {
   
        p=(struct Node *)malloc(sizeof(struct Node)); /*建立新插入的节点*/
        (*p).left=NULL;
        (*p).value=v;
        (*p).right=NULL;
        pre=root;                                                         /*开始寻找新插入的节点应该在的位置*/
        current=pre;
        while(current)                                                  /*只要current还未指向NULL*/
        {
   
            pre=current;                                                /*pre移动到current的位置*/
            if(v>(*pre).value)                                         /*若v比当前节点的序号大,current则移动到当前节点的右子节点*/
            {
   
                current=(*pre).right;
            }
            if(v<(*pre).value)                                          /*若v比当前节点的序号小,current则移动到当前节点的左子节点*/
            {
   
                current=(*pre).left;
            }
            if(v==(*pre).value)                                        /*若v与当前节点的序号一致,说明序号已存在,终止循环,停止寻找*/
            {
   
                break;
            }
        }
        if((*pre).value<v)                                              /*连接新插入的节点和它的父节点*/
        {
   
            (*pre).right=p;
        }
        if((*pre).value>v)
        {
   
            (*pre).left=p;
        }
        if(v==(*pre).value)
        {
   
            printf("this value has existed\n");
        }
        printf("please add a number\n");
        scanf("%d",&v);
    }
    return root;
}

二叉树的插入操作并不难,与链表的插入区别不大,只是链表寻找插入的位置是逐个寻找,二叉树寻找插入的位置会有左右的选择。
这样插入新的节点,新的节点一定是叶节点。当然在保证二叉树的节点的序号正确的前提下,可以把节点插入二叉树两个节点之间,只是这样会比较麻烦。

遍历二叉树

遍历二叉树两种方法,其中一种为层序遍历,即自上而下对二叉树逐层遍历;另一种方法有三种表现形式,分别为前序、中序和后序。
遍历二叉树

前序遍历
A-B-D-H-I-E-J-C-F-G

void print(struct Node *root)
{
   
    if(root==NULL)
    {
   
        return;
    }
    printf("%d\n",
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值