009——二叉树

ops/2025/2/12 4:33:41/

目录

二叉树的五种基本形态:

1.二叉树可以是空树

2.只有一个根节点的树

3.斜树:只有左子树或右子树的树

4.左右孩子都有的树

二叉树的性质:

1.假设根节点是第一层,在二叉树的第i层上最多有2^(n-1)个结点

2.深度为k的二叉树,最多有(2^k)-1个结点

3.任意一个非空二叉树,度为0的结点数比度为2的结点数多一个

4.在完全二叉树中有无度为1的判断

5.具有N个结点的完全二叉树的深度为log2(N+1)(向下取整)或者(log2N)+1(向上取整)

6. 如果有一棵n个结点的完全二叉树,其结点编号按照层次序(从上到下,从左到右),则除根结点外,满足[i/2 , i, 2i, 2i+1]的规则

二叉树的存储方式

1.直接采用数组存储二叉树,将任意一个二叉树补成完全二叉树,不过这样容易造成空间上的浪费

2.二叉链表存储


二叉树是树中最常用的一种,即度为2的树(每个结点最多有两个孩子),在二叉树中,结点的度只有0、1、2这三种可能

二叉树的五种基本形态:

1.二叉树可以是空树

2.只有一个根节点的树

3.斜树:只有左子树或右子树的树

4.左右孩子都有的树

二叉树的性质:

1.假设根节点是第一层,在二叉树的第i层上最多有2^(n-1)个结点

解释:若想要结点数最多,则要求除叶子结点外,每个结点的度都为2

层数                                        该层结点数

一层:        根节点                        1

二层:        1*2                             2

三层            2*2                             4

四层            4*2                             8

 n层           2*2*...*2                    2^(n-1)

2.深度为k的二叉树,最多有(2^k)-1个结点

将所有层次的结点数相加,再根据等比数列求和公式可得

满二叉树

而有(2^k)-1个结点的树有被称作满二叉树,满二叉树没有度为1的结点

完全二叉树

对满二叉树的结点编号(从上到下再从左到右)从后面删除若干个连续的编号最大的结点,剩下的部分就是完全二叉树

如下图删除15.14.13

同时,对于完全二叉树来说,度为1的结点要么没有,要么只有一个

满二叉树也是完全二叉树

3.任意一个非空二叉树,度为0的结点数比度为2的结点数多一个

解释:

按照度来分,我们可以将其分成度分别为0,1,2的结点:

n = n0 + n1 + n2

按照有无父亲,或者说是是否可以当作孩子结点,我们可以分成根节点和其他结点:

n = 1 + (n-1)

而在这(n-1)个孩子结点里,我们可以再将每个结点看作父亲,

度为0的父亲没有孩子        0 * n0

度为1的父亲一个孩子        1 * n1

度为2的父亲两个孩子        2 * n1

所以可以推出

n = 1 +  0 * n0 +  n1 + 2n1

n0 + n1 + n2  = 1 +   n1 + 2n1

                 n0 = n2 + 1

或者从连线个数的角度理解:

n个结点的树有n-1条连线

度为0的树向下有0条

度为1的树向下有n1条

度为2的树向下有2n2条

n1+n2+n0-1 =n1+2n2 

             n0-1=n2

4.在完全二叉树中有无度为1的判断

没有度为1的结点,n=n0+n2=n2+1+n2=2n2+1

有度为1的结点,n=n0+n1+n2=2n2+2

所以在完全二叉树中,结点数为奇数,没有度为1的结点;结点数为偶数,有度为1的结点且只有1个

5.具有N个结点的完全二叉树的深度为log2(N+1)(向下取整)或者(log2N)+1(向上取整)

6. 如果有一棵n个结点的完全二叉树,其结点编号按照层次序(从上到下,从左到右),则除根结点外,满足[i/2 , i, 2i, 2i+1]的规则

二叉树的存储方式

1.直接采用数组存储二叉树,将任意一个二叉树补成完全二叉树,不过这样容易造成空间上的浪费

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
#include<stdlib.h>
char data[1005];
int flag;//=0 左  =1右孩子 
int find(char fx)
{for (int i = 1; i < 1005; i++){if (data[i] == fx){return i;}}
}
int main()
{int n;char root;printf("读入数据个数:\n");scanf("%d", &n);for (int i = 0; i < 1005; i++){data[i] = ' ';}getchar();printf("读入根结点:\n");scanf("%c", &root);data[1] = root;char x, fx;//数据为x,fx为x的父亲  int fxi, xi;for (int i = 1; i <= n - 1; i++){getchar();printf("读入剩下的结点(x fx flag):\n");scanf("%c %c %d", &x, &fx, &flag);fxi = find(fx);//寻找父亲结点的下标 if (flag == 0){xi = 2 * fxi;}else {xi = 2 * fxi + 1;}data[xi] = x;}getchar();printf("查找某个结点的孩子父亲结点:\n");scanf("%c", &x);xi = find(x);if (xi == 1){printf("根节点,无父亲节点\n");}else {printf("父亲结点:%c\n", data[xi / 2]);}printf("孩子节点是:%c %c\n", data[2 * xi], data[2 * xi + 1]);return 0;
}

2.二叉链表存储

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
//二叉链表节点结构
typedef struct BTNode {char data;struct BTNode* left;//保存左孩子地址struct BTNode* right;//保存右孩子地址//struct BTNode* fa;//保存父亲的地址 
}BTNode, * BTree;
BTree initBTree(char root)
{BTNode* r = (BTNode*)malloc(sizeof(BTNode));if (r == NULL){printf("空间分配失败\n");return NULL;}r->data = root;r->left = r->right = NULL;//r->fa=NULL; return r;
}
BTNode* find(BTree r, char fx)
{if (r == NULL || r->data == fx){return r;}if (r->left != NULL){BTNode* ans = find(r->left, fx);if (ans != NULL && ans->data == fx){return ans;}}if (r->right != NULL){BTNode* ans = find(r->right, fx);if (ans != NULL && ans->data == fx){return ans;}}return NULL;
}BTree insert(BTree r, char x, char fx, int flag)
{BTNode* f = find(r, fx);if (f == NULL){printf("父亲节点不存在,不能插入\n");}else{BTNode* s = (BTNode*)malloc(sizeof(BTNode));//判断s==NULLs->data = x;s->left = s->right = NULL;//s->fa=f;if (flag == 0){f->left = s;}else {f->right = s;}}return r;
}
int main()
{int n;int flag;//=0 左  =1右孩子 BTree r = NULL;char root;printf("输入结点的总个数:\n");scanf("%d", &n);getchar();printf("输入根节点:\n");scanf("%c", &root);r = initBTree(root);char x, fx;for (int i = 1; i <= n - 1; i++){getchar();printf("输入结点信息(x, fx, flag):\n");scanf("%c %c %d", &x, &fx, &flag);r = insert(r, x, fx, flag);}getchar();printf("输入要查找的结点:\n");scanf("%c", &x);BTNode* p = find(r, x);if (p != NULL && p->left != NULL){printf("左孩子%c\n", p->left->data);}if (p != NULL && p->right != NULL){printf("右孩子%c\n", p->right->data);}return 0;
}


http://www.ppmy.cn/ops/124091.html

相关文章

【docker笔记8-镜像推送】

docker笔记8-镜像推送 一、基本命令二、案例1.Java demo2.打包镜像 一、基本命令 &#xff08;1&#xff09;推送镜像到远程仓库 docker tag local-image:tagname new-repo:tagname docker push new-repo:tagname这里首先要登录到docker&#xff0c;然后需要输入登录用户名和…

netty之SpringBoot+Netty+Elasticsearch收集日志信息数据存储

前言 将大量的业务以及用户行为数据存储起来用于分析处理&#xff0c;但是由于数据量较大且需要具备可分析功能所以将数据存储到文件系统更为合理。尤其是一些互联网高并发级应用&#xff0c;往往数据库都采用分库分表设计&#xff0c;那么将这些分散的数据通过binlog汇总到一个…

vite学习教程05、vite+vue2构建本地 SVG 图标

文章目录 前言一、构建本地SVG图标详细步骤1、安装开发依赖2、配置vite2.1、配置vite.config.js2.2、封装vite引入插件脚本 解决报错&#xff1a;can not find package fast-glob imported 二、实际应用应用1&#xff1a;未封装&#xff0c;直接vue应用应用2&#xff1a;封装vu…

BugReport中的App Processor wakeup字段意义

一、功耗字段意义&#xff1a; App processor wakeup:Netd基于xt_idletimer 待机下监视网络设备的收发工作状态&#xff0c;即当设备发生联网从休眠态变成为唤醒态时&#xff0c;会记录打醒者的uid(uid大于0)和网络类型(wifi或数据类型)、时间戳 实际日志&#xff1a;我们在B…

Linux: 网络: tcp_mem遭遇hard limit时,是否要上报警告?

tcp_mem: https://mzhan017.blog.csdn.net/article/details/142647143. 根据Linux内核的代码看,tcp_mem的设置是下面的默认值(按照当前系统所拥有内存容量的一个比例): static void __init tcp_init_mem(void) {unsigned long limit = nr_free_buffer_pages()

从零学编程- C语言-第18天

1.malloc 2.free 3.calloc 4.malloc 跟calloc 一个不能自动初始化一个能自动初始化 使用那个无所谓&#xff0c;看自己 calloc mallocmemset 5.realloc ​​​​​​​ ​​​​​​​ 6.申请空间是需要浪费时间的&#xff0c;频繁的添加空间耗时间&#xff0c;需要操作系…

mysql学习教程,从入门到精通,SQL 复制表(36)

1、SQL 复制表 在 SQL 中&#xff0c;复制表是一个常见的任务&#xff0c;通常用于备份、测试或数据迁移。下面是一个基本的指南&#xff0c;演示如何在不同的 SQL 数据库管理系统中复制表。 1.1. 使用 CREATE TABLE ... AS SELECT ... 语句 这种方法适用于大多数 SQL 数据库…

从零学编程-C语言-第17天

今天是学习C语言的第17天 时间&#xff1a;2024/10/6 21:16分 使用编译器&#xff1a;vs2019 此贴记录自己的成长 今天学习内容如下 1.自定义类型-结构体 结构体 枚举 联合 //结构体 struct stu {char name[20]; }s1, s2; 这里是全局变量 int main() {struct stu s1,s2 …