数据结构与算法⑭(第四章_下)二叉树的模拟实现和遍历代码(下)

简介: 数据结构与算法⑭(第四章_下)二叉树的模拟实现和遍历代码

数据结构与算法⑭(第四章_下)二叉树的模拟实现和遍历代码(上):https://developer.aliyun.com/article/1513431

4.3求二叉树第k层结点个数

求当前树的第k层结点个数=其左子树第k-1层结点个数+其右子树第k-1层结点个数,k=1时返回1

比如上图K=3,求A的第3层结点个数就是求B的第2层的节点+C的第2层的结点。

 
int TreeKLevelSize(BTNode* root, int  k) 
{
    assert(k > 0);
    if (root == NULL) //空结点返回0
    {
        return 0;
    }
    if (k == 1)
    {
        return 1;
    }
    return TreeKLevelSize(root->left, k - 1) 
        +  TreeKLevelSize(root->right, k - 1);
}

4.4查找树里面值为x的那个结点

思路:空就返回空,找到了就返回这个结点,没找到就到左子树和右子树去找,都没找到就返回空

 
BTNode* TreeFind(BTNode* root, BTDataType x) 
{
    if (root == NULL)
    {
        return NULL;
    }
    if (root->data == x) 
    {
        return root;
    }
 
    BTNode* lret = TreeFind(root->left, x);
    if (lret) 
    {
        return lret;
    }
 
    BTNode* rret = TreeFind(root->right, x);
    if (rret) 
    {
        return rret;
    }
 
    return NULL;
}

比如要找E的位置:(找不到前都返回空)


4.5 二叉树销毁

这里采用后序遍历的销毁方式,因为用前序和中序要保存结点。

 
// 一般,如果选择一级指针,存在野指针问题,调用BinaryTreeDestory的人,把指针置空
// 这样保持接口的一致性
void BinaryTreeDestory(BTNode* root)
{
    if (root == NULL)
    {
        return;
    }
    BinaryTreeDestory(root->left);
    BinaryTreeDestory(root->right);
 
    //printf("%p %c\n", root, root->data);
    free(root);
    root = NULL;
}


前面函数的代码和测试:

 
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
 
typedef char BTDataType;
 
typedef struct BinaryTreeNode 
{
    struct BinaryTreeNode* left;       // 记录左节点
    struct BinaryTreeNode* right;      // 记录右节点
    BTDataType data;                   // 存储数据
} BTNode;
 
//创建新节点
BTNode* CreateNode(BTDataType x) 
{
    BTNode* new_node = (BTNode*)malloc(sizeof(BTNode));
    if (new_node == NULL)
    {
        printf("malloc failed!\n");
        exit(-1);
    }
    new_node->data = x;
    new_node->left = new_node->right = NULL;
 
    return new_node;
}
 
//手动创建二叉树 
BTNode* CreateBinaryTree()
{
    BTNode* nodeA = CreateNode('A');
    BTNode* nodeB = CreateNode('B');
    BTNode* nodeC = CreateNode('C');
    BTNode* nodeD = CreateNode('D');
    BTNode* nodeE = CreateNode('E');
    BTNode* nodeF = CreateNode('F');
 
    nodeA->left = nodeB;         //           A
    nodeA->right = nodeC;        //       B        C
    nodeB->left = nodeD;         //    D        E    F
    nodeC->left = nodeE;
    nodeC->right = nodeF;
 
    return nodeA;
}
 
//二叉树前序遍历
void PreOrder(BTNode* root)
{
    //首先判断根是否为空,为空就返回
    if (root == NULL)
    {
        printf("NULL ");    // 暂时打印出来,便于观察       
        return;
    }
    //走到这里说明不为空,根据前序遍历,先访问根节点
    printf("%c ", root->data);
 
    //然后遍历左子树(利用递归)
    PreOrder(root->left);
 
    //最后遍历右子树(利用递归)
    PreOrder(root->right);
 
    //           A
    //       B        C
    //    D        E    F        前序: 根 左 右
    //执行输出:  A B D NULL NULL NULL C E NULL NULL F NULL NULL
}
 
//二叉树中序遍历
void InOrder(BTNode* root) 
{
    if (root == NULL) 
    {
        printf("NULL ");  
        return;
    }
 
    InOrder(root->left);
 
    printf("%c ", root->data);
 
    InOrder(root->right);
     //           A
     //       B        C
     //    D        E    F        中序:左 根 右
     //执行输出:NULL D NULL B NULL A NULL E NULL C NULL F NULL
}
 
//二叉树后序遍历
void PostOrder(BTNode* root) 
{
    if (root == NULL) 
    {
        printf("NULL ");
        return;
    }
 
    PostOrder(root->left);
 
    PostOrder(root->right);
 
    printf("%c ", root->data);
    //           A
    //       B        C
    //    D        E    F        后序:左  右  根
    //执行输出:NULL NULL D NULL B NULL NULL E NULL NULL F C A
}
 
int TreeSize(BTNode* root) 
{
    return root == NULL ? 0 
        : TreeSize(root->left) + TreeSize(root->right) + 1;
}
 
int TreeLeafSize(BTNode* root) 
{
    if (root == NULL) 
    {
        return 0;
    }
 
    if (root->left == NULL && root->right == NULL) 
    {
        return 1;
    }
 
    return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
 
int TreeKLevelSize(BTNode* root, int  k) 
{
    assert(k > 0);
    if (root == NULL) 
    {
        return 0;
    }
    if (k == 1)
    {
        return 1;
    }
    return TreeKLevelSize(root->left, k - 1) 
        +  TreeKLevelSize(root->right, k - 1);
}
 
// 查找树里面值为x的那个节点
BTNode* TreeFind(BTNode* root, BTDataType x) 
{
    if (root == NULL)
    {
        return NULL;
    }
    if (root->data == x) 
    {
        return root;
    }
 
    BTNode* lret = TreeFind(root->left, x);
    if (lret) 
    {
        return lret;
    }
 
    BTNode* rret = TreeFind(root->right, x);
    if (rret) 
    {
        return rret;
    }
 
    return NULL;
}
 
// 一般,如果选择一级指针,存在野指针问题,调用BinaryTreeDestory的人,把指针置空
// 这样保持接口的一致性
void BinaryTreeDestory(BTNode* root)
{
    if (root == NULL)
    {
        return;
    }
    BinaryTreeDestory(root->left);
    BinaryTreeDestory(root->right);
 
    //printf("%p %c\n", root, root->data);
    free(root);
    root = NULL;
}
 
int main()
{
    BTNode* root = CreateBinaryTree();
    PreOrder(root);
    printf("\n");
 
    InOrder(root);
    printf("\n");
 
    PostOrder(root);
    printf("\n");
 
    printf("TreeSize:%d\n", TreeSize(root));
 
    printf("TreeLeafSize:%d\n", TreeLeafSize(root));
 
    printf("TreeKLevelSize:%d\n", TreeKLevelSize(root, 3));
 
    printf("TreeFind:%p\n", TreeFind(root, 'E'));
    printf("TreeFind:%p\n", TreeFind(root, 'F'));
    printf("TreeFind:%p\n", TreeFind(root, 'X'));//打印0 :找不到
 
    BinaryTreeDestory(root);
    root = NULL;
    return 0;
}


5.二叉树广度优先遍历

5.1层序遍历

层序遍历(Level Traversal):设二叉树的根节点所在的层数为1的情况下,

从二叉树的根节点出发,首先访问第1层的树根节点,然后再从左到右访问第2层上的节点。

接着是第3层的节点……以此类推,自上而下、从左向右地逐层访问树的节点。

该如何实现层序遍历呢? 可以利用队列的性质来实现。

之前再讲过队列,这里你可以选择自己实现一个队列。

如果不想实现就直接复制即可,因为这里重点要学的是层序遍历。

这里就先不实现了,下一篇写写二叉树OJ,下下篇再实现(最下面已附链接)

6.笔试选择题

练习1:

2-3树是一种特殊的树,它满足两个条件:

(1) 每个内部结点有两个或三个子结点

(2) 所有的叶结点到根的距离相同

如果一颗2-3树有10个结点,那么它有( )个叶结点。

A.7

B.8

C.7 或 8

D.6


练习2:

设某种二叉树有如下特点:每个结点要么是叶子结点,要么有2棵子树。假如一棵这样的二叉树中有m(m>0)个叶子结点,那么该二叉树上的结点总数为( )

A.2m+1

B.2(m-1)

C.2m-1

D.2m

练习3:

设根结点的深度为1,则一个拥有n个结点的二叉树的深度一定在( )区间内

A.[log(n + 1),n]

B.[logn,n]

C.[log(n + 1),n - 1]

D.[log(n + 1),n + 1]

练习4:

对任意一颗二叉树,设N0、N1、N2分别是度为0、1、2的结点数,则下列式子中一定正确的是( )

A.N0 = N2 + 1

B.N1 = N0 + 1

C.N2 = N0 + 1

D.N2 = N1 + 1

练习5:

二叉树的( )遍历相当于广度优先遍历,( )遍历相当于深度优先遍历

A.前序 中序

B.中序 前序

C.层序 后序

D.层序 前序


练习6:

如果一颗二叉树的前序遍历的结果是ABCD,则满足条件的不同的二叉树有( )种

A.13

B.14

C.15

D.16

答案:

1.答案:D

根据题目意思,每一个非叶子节点至少有两个孩子节点,并且叶子节点都在同一层,所以,假设树的高度为h, 则二三树种最小的节点个数为满二叉树的个数:2^h - 1, 最大个数: (3^h - 1) / 2。所以 2^h - 1 < 10 < (3^h - 1) / 2, h为3,结构是1(3(2,2,2))。所以叶节点个数为6


2.答案:C


根据二叉树的性质,在任意的二叉树中,度为0的节点比度为2的节点多了1个----见课件


现在叶子节点为m个,即度为0的节点有m个,那度为2的节点个数就为m-1个


而题目说该二叉树中只有度为2和度为0的节点 ,因此总的节点数就为:m+m-1 = 2m-1


3答案:A


最大深度: 即每次只有一个节点,次数二叉树的高度为n,为最高的高度


最小深度: 此树为完全二叉树, 如果是完全二叉树


根据二叉树性质,完全二叉树的高低为 h = log(n+1)向上取整


4答案:A


节点总数N: N = N0 + N1 + N2


度和边的关系: N - 1 = 0 * N0 + 1 * N1 + 2 * N2


上面两个式子可以推出: N0 + N1 + N2 - 1 = N1 + 2 * N2


可得: N0 = N2 + 1


5答案:D(前中后序遍历都可以称为深度优先遍历,但是单选的话就选前序)


广度优先需要把下一步所有可能的位置全部遍历完,才会进行更深层次的遍历,


层序遍历就是一种广度优先遍历。


深度优先是先遍历完一条完整的路径(从根到叶子的完整路径),才会向上层折返,


再去遍历下一个路径,前序遍历就是一种深度优先遍历。


6答案:B


首先这棵二叉树的高度一定在3~4层之间:


三层:


A(B(C,D),()), A((),B(C,D)), A(B(C,()),D), A(B((),C),D),


A(B,C(D,())), A(B,C((),D))


四层:


如果为四层,就是单边树,每一层只有一个节点,除过根节点,其他节点都有两种选择,


在上层节点的左边还是右边,所以2*2*2共8种,总共为14种。

本篇完

目录
相关文章
|
14天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
69 1
|
2月前
|
机器学习/深度学习 存储 算法
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
104 4
|
2月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
2月前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
69 5
|
2月前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
151 8
|
2月前
|
算法
树的遍历算法有哪些?
不同的遍历算法适用于不同的应用场景。深度优先搜索常用于搜索、路径查找等问题;广度优先搜索则在图的最短路径、层次相关的问题中较为常用;而二叉搜索树的遍历在数据排序、查找等方面有重要应用。
42 2
|
2月前
|
机器学习/深度学习 JSON 算法
二叉树遍历算法的应用场景有哪些?
【10月更文挑战第29天】二叉树遍历算法作为一种基础而重要的算法,在许多领域都有着不可或缺的应用,它为解决各种复杂的问题提供了有效的手段和思路。随着计算机科学的不断发展,二叉树遍历算法也在不断地被优化和扩展,以适应新的应用场景和需求。
58 0
|
3月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
37 1
|
3月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
35 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)