『数据结构与算法』解读树(Tree)和二叉树(Binary Tree)!
『数据结构与算法』解读树(Tree)和二叉树(Binary Tree)! |
文章目录
- 一. 树
- 1.1. 树的定义
- 1.2. 树的基本术语
- 1.3. 树的性质
- 二. 二叉树
- 2.1. 二叉树的定义
- 2.2. 几种特殊的二叉树
- 2.3. 二叉树的性质
- 2.4. 二叉树的存储结构
- 2.4.1. 二叉树的顺序存储结构
- 2.4.2. 二叉树的链式存储结构
- 2.5. 本节总结
- 三. 二叉树的遍历
- 3.1. 二叉树遍历的概念
- 3.2. 前序中序后序层次遍历
- 3.3. 二叉树遍历(前序,中序,后序)递归算法(C++)
- 3.4. 二叉树的构造(通过遍历)
- 四. 二叉树的基本运算及其实现(c++)
- 4.1. 创建二叉树
- 4.2. 销毁二叉树
- 4.3. 查找节点
- 4.4. 找孩子节点(左或右)
- 4.5. 求树的高度
- 4.6. 输出二叉树
- 4.7. 代码总结
- 五. 线索二叉树
- 5.1. 线索二叉树的概念
- 5.2. 线索化二叉树
- 5.3. 遍历线索化二叉树
- 六. 哈夫曼树
- 6.1. 哈夫曼树的定义
- 6.2. 构造哈夫曼树
- 6.3. 哈夫曼树编码
- 七. 以上内容总结
- 7.1. 二叉树遍历
- 7.2. 二叉树构造
- 7.3. 线索二叉树
- 7.4. 哈夫曼树
之前解读的内容如下:
- 『数据结构与算法』解读链表!
- 『数据结构与算法』解读栈(Stack)和队列(Queue)!
一. 树
1.1. 树的定义
树是 n(n≥0)n(n \geq 0)n(n≥0)个节点的有限集。当 n=0n = 0n=0 时,称为空树。在任意一颗非空树中应满足:
- ①有且仅有一个特定的称为根的结点。
- ②当 n>1n>1n>1 时, 其余节点可分为 m(m>0)m (m > 0)m(m>0)个互不相交的有限集 T1,…,TmT_1,…, T_mT1,…,Tm , 其中每个集合本身又是一颗树,并且称为根的子树。
显然,树的定义是递归的,即在树的定义中又用到了其自身,树是一种递归的数据结构。树作为一种逻辑结构,同时也是一种分层结构,具有以下两个特点:
- ①树的根结点没有前驱, 除根结点外的所有结点有且只有一个前驱。
- ②树中所有结点可以有零个或多个后继。
树适合于表示具有层次结构的数据。树中的某个结点(除根结点)最多只和上一层的一个结点(即其父结点)有直接关系,根结点没有直接上层结点,因此在 nnn 个结点的树中有 n−1n -1n−1条边。 而树中每个结点与其下一层的零个或多个结点(即其子女结点〉有直接关系。
1.2. 树的基本术语
1、节点的度与树的度: 树中一个节点的子树个数称为该节点的度 。树中各节点的度最大值称为树的度,通常将度为 mmm 的树称为 mmm 次树或者 mmm 叉树 。
2、分支节点与叶节点: 度不为零的节点称非终端,又叫分支节点。度为零的节点称终端或叶节点 (或叶子节点)。度为1的节点称为单分支节点;度为2的节点称为双分支节点,依此类推。
3、路径与路径长度: 两个节点 did_idi 和 djd_jdj 的节点序列(di,di1,di2,…,dj)(d_i,d_{i1},d_{i2},…,d_j)(di,di1,di2,…,dj) 称为路径。其中<dx,dy><d_{x}, \ d_{y}><dx,dy>是分支。路径长度等于路径所通过的节点数目减1(即路径上分支数目)。
4、孩子节点 、双亲节点和兄弟节点: 在一棵树中 ,每个节点的后继,被称作该节点的孩子节点(或子女节点 )。相应地 ,该节点被称作孩子节点的双亲节点(或父母节点)。具有同一双亲的孩子节点互为兄弟节点。
5、子孙节点和祖先节点: 在一棵树中 ,一个节点的所有子树中节点称为该节点的子孙节点 。从根节点到达一个的路径上经过所有被称作该祖先节点。
6、节点的层次和树高度: 树中的每个节点都处在一个层次上。 节点的层次从树根开始定义,根节点第1层,它的孩子节点为第2层,以此类推,一个节点所在的层次为其双亲节点所在的层次为其双亲加1。树中节点的最大层次称为树高度 (或树的深度)。
7、有序树和无序树: 若树中各节点的子树是按照一定次序从左 向右安排的,且相对次序是不能随意变换的,则称为有序树,否则称为无序树。
8、森林: n(n>0)n(n>0)n(n>0) 个互不相交的树集合称为森林。
1.3. 树的性质
二. 二叉树
2.1. 二叉树的定义
递归定义: 二叉树是有限的节点集合。
- 这个集合或者是空。
- 或者由一个根节点和两棵互不相交的左子树和右子树的二叉树组成。
二叉树与度为2的有序树的区别:(二叉树是有序树,若将其左、右子树颠倒, 则成为另一棵不同的二叉树)
- ①度为2的树至少有3个结点,而二叉树可以为空。
- ②度为2的有序树的孩子的左右次序是相对于另一孩子而言的, 若某个结点只有一个孩子,则这个孩子就无须区分其左右次序,而二叉树无论其孩子数是否为2 ,均需确定其左右次序,即二叉树的结点次序不是相对于另一结点而言, 而是确定的。
2.2. 几种特殊的二叉树
③二又排序树。左子树上所有结点的关键字均小于根结点的关键字: 右子树上的所有结点的关键宇均大于根结点的关键宇; 左子树和l右子树又各是一棵二叉排序树。
④平衡二又树。树上任一结点的左子树和右子树的深度之差不超过1。
2.3. 二叉树的性质
性质5: 具有 n(n>0)n(n>0)n(n>0) 个节点的完全二叉树的高度为 ⌈log2(n+1)⌉\left\lceil\log _{2}(n+1)\right\rceil⌈log2(n+1)⌉ 或者 ⌊log2n⌋+1\left\lfloor\log _{2} n\right\rfloor+1⌊log2n⌋+1。证明如下:
2.4. 二叉树的存储结构
2.4.1. 二叉树的顺序存储结构
2.4.2. 二叉树的链式存储结构
typedef int ElemType;
typedef struct node
{ElemType data;struct node *lchild, *rchild;
}BTNode;
2.5. 本节总结
- ① nnn 个不同的节点构造的二叉树的个数?
- ② 二叉树中节点计算方法
- ③ 完全二叉树中节点计算方法
- ④ 满二叉树中节点计算方法
- ① 二叉树的顺序存储结构
- ② 二叉树的链式存储结构
三. 二叉树的遍历
3.1. 二叉树遍历的概念
3.2. 前序中序后序层次遍历
- 1、前序遍历
- 2、中序遍历
- 3、后序遍历
- 4、层次遍历
- 快速写遍历的方法:
3.3. 二叉树遍历(前序,中序,后序)递归算法(C++)
#include <iostream>
#define MaxSize 50
using namespace std;
//二叉树节点(结构体定义)
typedef char ElemType;
typedef struct node
{ElemType data;struct node *lchild, *rchild;
} BTNode;
//======================= 创建二叉树 =========================
void createBTNode(BTNode *&b, char *str) //由str===>二叉链b
{//我们设置一个栈,这里采用顺序栈实现;BTNode *St[MaxSize], *p;int top = -1, k, j = 0;char ch; //字符b = NULL; //建立的二叉链初始时为空ch = str[j];while (ch != '\0') //str未扫描完时循环{switch (ch){case '(':top++; //栈顶指针上移St[top] = p; //进栈k = 1;break;case ')':top--;break;case ',':k = 2;break;default: //遇到节点值p = (BTNode *)malloc(sizeof(BTNode));p->data = ch;p->lchild = p->rchild = NULL; //左右子树都设置为空if (b == NULL) //一个节点都没创建,此时p为二叉树根节点;b = p;else //已经建立二叉树根节点{switch (k) //判断左右子树{case 1:St[top]->lchild = p;break;case 2:St[top]->rchild = p;break;}}}j++;ch = str[j]; //继续扫描str;}
}
//============================ 1. 前序递归算法 =========================
void preOrder(BTNode *b)
{if (b != NULL){cout << b->data; //访问根节点;preOrder(b->lchild);preOrder(b->rchild);}
}
//============================ 2. 中序递归算法 =========================
void inOrder(BTNode *b)
{if (b != NULL){inOrder(b->lchild);cout << b->data; //访问根节点;inOrder(b->rchild);}
}
//============================ 3. 后序递归算法 =========================
void postOrder(BTNode *b)
{if (b != NULL){postOrder(b->lchild);postOrder(b->rchild);cout << b->data; //访问根节点;}
}
int main()
{BTNode *btree = new BTNode;char a[] = "A(B(D(,G)),C(E,F))"; //字符数组createBTNode(btree, a);//1、先序遍历cout << "================================1.preOrder: " << endl;preOrder(btree);//2、中序遍历cout << "\n================================2.InOrder: " << endl;inOrder(btree);//3、后序遍历cout << "\n================================3.postOrder: " << endl;postOrder(btree);cout << endl;system("pause");return 0;
}
三种遍历输出结果:
================================1.preOrder:
ABDGCEF
================================2.InOrder:
DGBAECF
================================3.postOrder:
GDBEFCA
请按任意键继续. . .
3.4. 二叉树的构造(通过遍历)
由二叉树的先序序列和中序序列可以唯一地确定一棵二叉树。
- 在先序遍历序列中,第一个结点一定是二叉树的根结点;而在中序遍历中,根结点必然将中序序列分割成两个子序列,前一个子序列是根结点的左子树的中序序列,后一个子序列是根结点的右子树的中序序列。根据这两个子序列,在先序序列中找到对应的左子序列和右子序列。在先序序列中, 左子序列的第一个结点是左子树的根结点,右子序列的第一个结点是右子树的根结点。如此递归地进行下去,便能唯一地确定这棵二叉树。
同理,由二叉树的后序序列和中序序列也可以唯一地确定一棵二叉树。
- 因为后序序列的最后一个结点就如同先序序列的第一个结点,可以将中序序列分割成两个子序列,然后来用类似的方法递归地进行划分,进而得到一棵二叉树。
由二叉树的层序序列和中序序列也可以唯一地确定一棵二叉树,实现方法留给读者思考。
- 需要注意的是,若只知道二叉树的先序序列和后序序列,则无法唯一确定一棵二叉树。
四. 二叉树的基本运算及其实现(c++)
4.1. 创建二叉树
创建二叉树
#include <iostream>
#define MaxSize 50
using namespace std;
//二叉树节点(结构体定义)
typedef char ElemType;
typedef struct node
{ElemType data;struct node *lchild, *rchild;
} BTNode;
//========================================1、创建二叉树
void createBTNode(BTNode *&b, char *str) //由str===>二叉链b
{//我们设置一个栈,这里采用顺序栈实现;BTNode *St[MaxSize], *p;int top = -1, k, j = 0;char ch; //字符b = NULL; //建立的二叉链初始时为空ch = str[j];while (ch != '\0') //str未扫描完时循环{switch (ch){case '(':top++; //栈顶指针上移St[top] = p; //进栈k = 1;break;case ')':top--;break;case ',':k = 2;break;default: //遇到节点值p = (BTNode *)malloc(sizeof(BTNode));p->data = ch;p->lchild = p->rchild = NULL; //左右子树都设置为空if (b == NULL) //一个节点都没创建,此时p为二叉树根节点;b = p;else //已经建立二叉树根节点{switch (k) //判断左右子树{case 1:St[top]->lchild = p;break;case 2:St[top]->rchild = p;break;}}}j++;ch = str[j]; //继续扫描str;}
}
//========================================2、打印二叉树
void dispBTNode(BTNode *b)
{if (b != NULL){cout << b->data;if (b->lchild != NULL || b->rchild != NULL){cout << "(";dispBTNode(b->lchild);if (b->rchild != NULL) //递归处理左子树;cout << ",";dispBTNode(b->rchild); //递归处理右子树;cout << ")" << endl;}}
}int main()
{BTNode *btree = new BTNode;char a[] = "A(B(D(,G)),C(E,F))"; //字符数组createBTNode(btree, a);dispBTNode(btree);system("pause");return 0;
}
A(B(D(,G)),C(E,F))
请按任意键继续. . .
4.2. 销毁二叉树
//========================================3、销毁二叉树
void destroyBT(BTNode *&b) //指针的引用
{if (b == NULL)return;else{destroyBT(b->lchild);destroyBT(b->rchild);free(b); //剩下一个节点*b, 直接释放;}
}
4.3. 查找节点
//========================================4、查找节点
BTNode *findNode(BTNode *b, ElemType x) //返回指针类型;
{BTNode *p;if (b == NULL)return NULL;else if (b->data == x)return b;else{p = findNode(b->lchild, x);if (p != NULL)return p;else{return findNode(b->rchild, x);}}
}
4.4. 找孩子节点(左或右)
//========================================5、找孩子节点
BTNode *lchildNode(BTNode *p)
{return p->lchild;
}
BTNode *rchildNode(BTNode *p)
{return p->rchild;
}
4.5. 求树的高度
//========================================6、求树的高度
int btNodeDepth(BTNode *b)
{int lchildDep, rchildDep;if (b == NULL) //空数的高度为0return 0;else{lchildDep = btNodeDepth(b->lchild); //求左子树的高度rchildDep = btNodeDepth(b->rchild); //求右子树的高度return (lchildDep > rchildDep) ? (lchildDep + 1) : (rchildDep + 1);}
}
4.6. 输出二叉树
//========================================2、输出二叉树
void dispBTNode(BTNode *b)
{if (b != NULL){cout << b->data;if (b->lchild != NULL || b->rchild != NULL){cout << "(";dispBTNode(b->lchild);if (b->rchild != NULL) //递归处理左子树;cout << ",";dispBTNode(b->rchild); //递归处理右子树;cout << ")";}}
}
4.7. 代码总结
#include <iostream>
#define MaxSize 50
using namespace std;
//二叉树节点(结构体定义)
typedef char ElemType;
typedef struct node
{ElemType data;struct node *lchild, *rchild;
} BTNode;
//========================================1、创建二叉树
void createBTNode(BTNode *&b, char *str) //由str===>二叉链b
{//我们设置一个栈,这里采用顺序栈实现;BTNode *St[MaxSize], *p;int top = -1, k, j = 0;char ch; //字符b = NULL; //建立的二叉链初始时为空ch = str[j];while (ch != '\0') //str未扫描完时循环{switch (ch){case '(':top++; //栈顶指针上移St[top] = p; //进栈k = 1;break;case ')':top--;break;case ',':k = 2;break;default: //遇到节点值p = (BTNode *)malloc(sizeof(BTNode));p->data = ch;p->lchild = p->rchild = NULL; //左右子树都设置为空if (b == NULL) //一个节点都没创建,此时p为二叉树根节点;b = p;else //已经建立二叉树根节点{switch (k) //判断左右子树{case 1:St[top]->lchild = p;break;case 2:St[top]->rchild = p;break;}}}j++;ch = str[j]; //继续扫描str;}
}
//========================================2、输出二叉树
void dispBTNode(BTNode *b)
{if (b != NULL){cout << b->data;if (b->lchild != NULL || b->rchild != NULL){cout << "(";dispBTNode(b->lchild);if (b->rchild != NULL) //递归处理左子树;cout << ",";dispBTNode(b->rchild); //递归处理右子树;cout << ")";}}
}
//========================================3、销毁二叉树
void destroyBT(BTNode *&b) //指针的引用
{if (b == NULL)return;else{destroyBT(b->lchild);destroyBT(b->rchild);free(b); //剩下一个节点*b, 直接释放;}
}//========================================4、查找节点
BTNode *findNode(BTNode *b, ElemType x) //返回指针类型;
{BTNode *p;if (b == NULL)return NULL;else if (b->data == x)return b;else{p = findNode(b->lchild, x);if (p != NULL)return p;else{return findNode(b->rchild, x);}}
}
//========================================5、找孩子节点
BTNode *lchildNode(BTNode *p)
{return p->lchild;
}
BTNode *rchildNode(BTNode *p)
{return p->rchild;
}//========================================6、求树的高度
int btNodeDepth(BTNode *b)
{int lchildDep, rchildDep;if (b == NULL) //空数的高度为0return 0;else{lchildDep = btNodeDepth(b->lchild); //求左子树的高度rchildDep = btNodeDepth(b->rchild); //求右子树的高度return (lchildDep > rchildDep) ? (lchildDep + 1) : (rchildDep + 1);}
}int main()
{BTNode *btree = new BTNode;char a[] = "A(B(D(,G)),C(E,F))"; //字符数组cout << "====================1. createBTNode ==========================" << endl;createBTNode(btree, a);cout << "====================2. dispBTNode ==========================" << endl;dispBTNode(btree);cout << "\n====================3. btNodeDepth ==========================" << endl;cout << "\ndepth of tree: " << btNodeDepth(btree) << endl;cout << "====================4. findNode ==========================" << endl;ElemType find = 'D';BTNode *p;p = findNode(btree, find);cout << p->data << endl;cout << "====================5. destroyBT ==========================" << endl;destroyBT(btree);system("pause");return 0;
}
运行结果:
====================1. createBTNode ==========================
====================2. dispBTNode ==========================
A(B(D(,G)),C(E,F))
====================3. btNodeDepth ==========================depth of tree: 4
====================4. findNode ==========================
D
====================5. destroyBT ==========================
请按任意键继续. . .
五. 线索二叉树
5.1. 线索二叉树的概念
回顾:
相关概念:
5.2. 线索化二叉树
线索二叉树过程
5.3. 遍历线索化二叉树
中序线索二叉树的中序遍历示例演示!
六. 哈夫曼树
6.1. 哈夫曼树的定义
6.2. 构造哈夫曼树
6.3. 哈夫曼树编码
建立哈夫曼树示例的演示!
七. 以上内容总结
7.1. 二叉树遍历
- 例子1:
- 例子2:
7.2. 二叉树构造
7.3. 线索二叉树
7.4. 哈夫曼树
- 最后提醒: 以上代码会持续的更新中!
『数据结构与算法』解读树(Tree)和二叉树(Binary Tree)!相关推荐
- 由任意二叉树的前序遍历序列和中序遍历序列求二叉树的思想方法_算法与数据结构基础 - 二叉树(Binary Tree)...
二叉树基础 满足这样性质的树称为二叉树:空树或节点最多有两个子树,称为左子树.右子树, 左右子树节点同样最多有两个子树. 二叉树是递归定义的,因而常用递归/DFS的思想处理二叉树相关问题,例如Leet ...
- 废柴日记6:迟到的『构造最小生成树算法』③
================================================= 废柴日记6:迟到一个月的『构造最小生成树算法』· 其三 ====================== ...
- 废柴日记7:迟到的『构造最小生成树算法』④
================================================= 废柴日记7:迟到的『构造最小生成树算法』· 其四(完结撒花) =================== ...
- 数据结构与算法之2-3-4树
数据结构与算法之2-3-4树 原文来自个人博客(求访问/关注/收藏): https://bbing.com.cn/ CSDN个人博客不定期转载 平衡树 [外链图片转存失败,源站可能有防盗链机制,建议将 ...
- 【数据结构】二叉树 (Binary Tree)
目录 一. 什么是树? 二. 二叉树 特殊二叉树 二叉树的性质 二叉树的存储 二叉树的遍历 二叉树的基本操作 一.什么是树? 之前咱们学习了一些简单的数据结构,如顺序表,链表,这些都是线性结构,线性结 ...
- 二叉树 Binary Tree
我怀着激动的心 走上了这颗树 今天是2021年11月12日 今天开始上树!!!!!! 生活中的树形结构: 树: 根节点: 一棵树有且只有一个根节点就是最上面的节点 兄弟节点: 每一行的节点 它们具 ...
- js遍历树节点下的所有子节点_【数据结构与算法】(3)——树和二叉树
树 树的基本概念 树是一种非线性的数据结构,样子如图所示: 树的主要特点是树中的数据是分层存储的,每个元素称为树的节点,最顶层有且只有一个元素,称为根节点,其余层可以有任意数量的节点.除了根节点,其余 ...
- 数据结构与算法一览(树、图、排序算法、搜索算法等)- Review
算法基础简介 - OI Wiki (oi-wiki.org) 文章目录 1. 数据结构介绍 1.1 什么是数据结构 1.2 数据结构分类 2. 链表.栈.队列:略 3. 哈希表:略 4. 树 4.1 ...
- 数据结构与算法学习笔记-树和二叉树
声明:本博客仅为本人学习途中做的笔记 采自青岛大学王卓老师的视频教学 主要内容为算法思路,具体代码实现还需修改后才能运行,望各位看官多多包涵,您的点赞与评论是对我最大的肯定! 1.树和二叉树的定义 数 ...
最新文章
- 三年 Git 使用心得 常见问题整理
- Android性能优化之App应用启动分析与优化
- Knative 应用在阿里云容器服务上的最佳实践
- STL常用对象,不会搞得C++跟没学一样
- Go_笔试题记录-指针与值类型实现接口的区别
- 冲刺阶段 day 6
- iphone固件降级_手机资讯:降级必备:Phone5如何下载备份SHSH文件
- 11款样式新颖的 jQuery/CSS3 网页菜单
- java 日期 yyyy_java日期中YYYY与yyyy的区别
- python 爬虫生成csv文件和图_python爬虫系列(4.2-python操作csv文件)
- 编写自己的tomcat, 并运行tomcat源码于eclipse中
- 《SAP CRM管理与实施指南》一一2.1 SAP CRM基础数据管理
- 佟年计算机大赛,佟年成电竞高手,老韩带老婆打比赛,solo内网被佟年轻松攻破...
- 过招多家大厂提炼的iOS面试心经(答案版)
- 电脑发送打印任务后打印机没有执行是怎么回事
- 【论文泛读76】将来自bert的提取信息和多种嵌入方法与深度神经网络集成在一起,以进行幽默检测
- 口红机 抖音口红机 女神赢口红系统源码 全开源可二次开发 微信游戏,公众号游戏,口红机源码安装部署、调试...
- 【日语】日语商务情景口语
- 【Java】抽象类继承的综合案例
- matlab 循环平稳检测,循环平稳信号处理完整的Matlab工具箱
热门文章
- 年份的读法与读数字不同
- 解决Ubuntu16.04软件商店无法加载
- OpenHD---低成本开源高清数字图传
- RESTful介绍(应用场合、常见的注解)
- C语言学习纯纯小白-1,C语言代码开头为什么要有#include <stdio.h>
- 【人工智能】未来三年(2018-2020),我们在新一代人工智能产业能做什么
- java研发网页数据采集
- html加入图片如何自动平铺,css怎么让图片平铺?
- Splunklive!2018北京站激情开场:合格的大数据处理平台到底是什么样子?
- “中国天眼”启动地外文明搜索,真的能找到吗?