二叉树的讲解

发布于:2022-10-17 ⋅ 阅读:(642) ⋅ 点赞:(0)

目录

一、定义

1.1 树的定义

1.2 树的种类

1.3 二叉树的定义

1.4 二叉树的遍历

1.5 二叉树相关知识点

 1.6 C语言实现二叉树的存储

二、特殊的二叉树

真二叉树(Proper Binary Tree)

满二叉树(Full Binary Tree)

完全二叉树(Complete Binary Tree)

 三、其他常用的计算机应用中的树

二叉查找树

 AVL树(自平衡二叉查找树)

红黑树


一、定义

1.1 树的定义

树是一种数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

每个节点有零个或多个子节点;
没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。

1.2 树的种类

无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;
有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
二叉树:每个节点最多含有两个子树的树称为二叉树;
满二叉树:叶节点除外的所有节点均含有两个子树的树被称为满二叉树;
完全二叉树:除最后一层外,所有层都是满节点,且最后一层缺右边连续节点的二叉树称为完全二叉树;
哈夫曼树(最优二叉树):带权路径最短的二叉树称为哈夫曼树或最优二叉树。 

1.3 二叉树的定义

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树,且有左右之分。

二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点。

1.4 二叉树的遍历

遍历表达法有4种方法:先序遍历、中序遍历、后序遍历、层次遍历

例如上图:
其先序遍历(又称先根遍历)为ABDCEF(根-左-右)
其中序遍历(又称中根遍历)为DBAECF(左-根-右)(仅二叉树有中序遍历)
其后序遍历(又称后根遍历)为DBEFCA(左-右-根)
其层次遍历为ABCDEF(同广度优先搜索)

1.5 二叉树相关知识点

名词 介绍
节点 包含一个数据元素及若干指向子树分支的信息
节点的度 一个节点拥有子树的数目称为节点的度
叶子节点 也称为终端节点,没有子树的节点或者度为零的节点
分支节点 也称为非终端节点,度不为零的节点称为非终端节点
树的度 树中所有节点的度的最大值
节点的层次 从根节点开始,假设根节点为第1层,根节点的子节点为第2层,依此类推,如果某一个节点位于第L层,则其子节点位于第L+1层
树的深度(高度) 也称为树的高度,树中所有节点的层次最大值称为树的深度
有序树 如果树中各棵子树的次序是有先后次序,则称该树为有序树
无序树 如果树中各棵子树的次序没有先后次序,则称该树为无序树
森林 由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根节点删除,则该树就变成了一片森林,森林中的树由原来根节点的各棵子树构成

 1.6 C语言实现二叉树的存储

代码:

#include <stdio.h>
#include <stdlib.h>
    
//树的结点
typedef struct node{
    int data;
    struct node* left;
    struct node* right;
} Node;
  
//树根
typedef struct {
    Node* root;
} Tree;
  
//创建树--插入数据
void insert(Tree* tree, int value){
    //创建一个节点,让左右指针全部指向空,数据为value
    Node* node=(Node*)malloc(sizeof(Node));
    node->data = value;
    node->left = NULL;
    node->right = NULL;
  
    //判断树是不是空树,如果是,直接让树根指向这一个结点即可
    if (tree->root == NULL){
        tree->root = node;
    } else {//不是空树
        Node* temp = tree->root;//从树根开始
        while (temp != NULL){
            if (value < temp->data){ //小于就进左儿子
                if (temp->left == NULL){
                    temp->left = node;
                    return;
                } else {//继续往下搜寻
                    temp = temp->left;
                }
            } else { //否则进右儿子
                if (temp->right == NULL){
                    temp->right = node;
                    return;
                }
                else {//继续往下搜寻
                    temp = temp->right;
                }
            }
        }
    }
    return;
}

//树的先序遍历 Preorder traversal
void preorder(Node* node){
    if (node != NULL)
    {
        printf("%d ",node->data);
        preorder(node->left);
        preorder(node->right);
    }
}
  
//树的中序遍历 In-order traversal
void inorder(Node* node){
    if (node != NULL)
    {
        inorder(node->left);
        printf("%d ",node->data);
        inorder(node->right);
    }
}

//树的后序遍历 Post-order traversal
void postorder(Node* node){
    if (node != NULL)
    {
        postorder(node->left);
        postorder(node->right);
        printf("%d ",node->data);
    }
}
  
int main(){
    Tree tree;
    tree.root = NULL;//创建一个空树
    int n;
    printf("请输出节点个数:");
    scanf("%d",&n);
  
    //输入n个数并创建这个树
    for (int i = 0; i < n; i++){
        int temp;
        scanf("%d",&temp);
        insert(&tree, temp);
    }
    
    printf("树的先序遍历结果:");
    preorder(tree.root);
    printf("\n");

    printf("树的中序遍历结果:");
    inorder(tree.root);
    printf("\n");

    printf("树的后序遍历结果:");
    postorder(tree.root);
    printf("\n");
  
    return 0;
}

 演示结果:

二、特殊的二叉树

真二叉树(Proper Binary Tree)

定义:所有节点的度要么为0,要么为2

满二叉树(Full Binary Tree)

 定义:所有节点的度要么为0,要么为2,且所有的叶子节点都在最后一层

 性质:假设满二叉树的高度为h(h ≥ 1),那么

            第 i 层的结点数量:2^{i-1}
            叶子结点数量:2^{h-1}
            总结点数:n = 2^{h} -  1 = 2^{0} + 2^{1} + 2^{2} … + 2^{h-1}
            高度:h = log_{2}(n+1)

 满二叉树一定是真二叉树,真二叉树不一定是满二叉树。

完全二叉树(Complete Binary Tree)

定义:叶子节点只会出现"最后2层",且"最后1层"的叶子节点都靠"左对齐"

满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。

 三、其他常用的计算机应用中的树

二叉查找树

二叉查找树(Binary Search Tree),又称二叉排序树(Binary Sort Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。

一棵空树或者是具有下列性质的二叉树:

(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
  特性:左子树<根<右子树 ,即二叉查找树的中序遍历是一个递增序列。

  没有键值相等的结点。

如下图的二叉查找树,中序遍历结果为 5、8、10、12、 13、15、16、18

C语言实现二叉查找树:

#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define ElemType int
#define  KeyType int

/* 二叉排序树的节点结构定义 */
typedef struct BiTNode
{
    int data;
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

//二叉排序树查找算法
int SearchBST(BiTree T, KeyType key, BiTree f, BiTree *p) {
    //如果 T 指针为空,说明查找失败,令 p 指针指向查找过程中最后一个叶子结点,并返回查找失败的信息
    if (!T) {
        *p = f;
        return FALSE;
    }
    //如果相等,令 p 指针指向该关键字,并返回查找成功信息
    else if (key == T->data) {
        *p = T;
        return TRUE;
    }
    //如果 key 值比 T 根结点的值小,则查找其左子树;反之,查找其右子树
    else if (key < T->data) {
        return SearchBST(T->lchild, key, T, p);
    }
    else {
        return SearchBST(T->rchild, key, T, p);
    }
}

int InsertBST(BiTree *T, ElemType e) {
    BiTree p = NULL;
    //如果查找不成功,需做插入操作
    if (!SearchBST((*T), e, NULL, &p)) {
        //初始化插入结点
        BiTree s = (BiTree)malloc(sizeof(BiTNode));
        s->data = e;
        s->lchild = s->rchild = NULL;
        //如果 p 为NULL,说明该二叉排序树为空树,此时插入的结点为整棵树的根结点
        if (!p) {
            *T = s;
        }
        //如果 p 不为 NULL,则 p 指向的为查找失败的最后一个叶子结点,只需要通过比较 p 和 e 的值确定 s 到底是 p 的左孩子还是右孩子
        else if (e < p->data) {
            p->lchild = s;
        }
        else {
            p->rchild = s;
        }
        return TRUE;
    }
    //如果查找成功,不需要做插入操作,插入失败
    return FALSE;
}

//删除函数
int Delete(BiTree *p)
{
    BiTree q, s;
    //情况 1,结点 p 本身为叶子结点,直接删除即可
    if (!(*p)->lchild && !(*p)->rchild) {
        *p = NULL;
    }
    else if (!(*p)->lchild) { //左子树为空,只需用结点 p 的右子树根结点代替结点 p 即可;
        q = *p;
        *p = (*p)->rchild;
        free(q);
    }
    else if (!(*p)->rchild) {//右子树为空,只需用结点 p 的左子树根结点代替结点 p 即可;
        q = *p;
        *p = (*p)->lchild;//这里不是指针 *p 指向左子树,而是将左子树存储的结点的地址赋值给指针变量 p
        free(q);
    }
    else {//左右子树均不为空,采用第 2 种方式
        q = *p;
        s = (*p)->lchild;
        //遍历,找到结点 p 的直接前驱
        while (s->rchild)
        {
            q = s;
            s = s->rchild;
        }
        //直接改变结点 p 的值
        (*p)->data = s->data;
        //判断结点 p 的左子树 s 是否有右子树,分为两种情况讨论
        if (q != *p) {
            q->rchild = s->lchild;//若有,则在删除直接前驱结点的同时,令前驱的左孩子结点改为 q 指向结点的孩子结点
        }
        else {
            q->lchild = s->lchild;//否则,直接将左子树上移即可
        }
        free(s);
    }
    return TRUE;
}

int DeleteBST(BiTree *T, int key)
{
    if (!(*T)) {//不存在关键字等于key的数据元素
        return FALSE;
    }
    else
    {
        if (key == (*T)->data) {
            Delete(T);
            return TRUE;
        }
        else if (key < (*T)->data) {
            //使用递归的方式
            return DeleteBST(&(*T)->lchild, key);
        }
        else {
            return DeleteBST(&(*T)->rchild, key);
        }
    }
}

void order(BiTree t)//中序输出
{
    if (t == NULL) {
        return;
    }
    order(t->lchild);
    printf("%d ", t->data);
    order(t->rchild);
}

int main()
{
    int i;
    int a[8] = { 12,8,18,5,10,15,13,16 };
    BiTree T = NULL;
    for (i = 0; i < 8; i++) {
        InsertBST(&T, a[i]);
    }
    printf("中序遍历二叉排序树:\n");
    order(T);
    printf("\n");
    printf("删除10后,中序遍历二叉排序树:\n");
    DeleteBST(&T, 10);
    order(T);
    printf("\n");
}

 实现结果:

 AVL树(自平衡二叉查找树)

AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis。

AVL树本质上还是一棵二叉搜索树,它的特点是:

1.本身首先是一棵二叉搜索树。
2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。

也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。 

如下图所示: 

 

红黑树

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。红黑树是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。 

红黑树是每个结点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,红黑树特征: 

1. 结点是红色或黑色。
2. 根结点是黑色。
3. 所有叶子都是黑色。(叶子是NIL结点)
4. 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。 

6. 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长

如下图所示: 

 

 


网站公告

今日签到

点亮在社区的每一天
去签到