树的概念及结构
树的相关概念
- 节点的度:一个节点含有的子树的个数成为该节点的度。
- 叶子节点:度为0的节点成为叶子节点。
- 子孙:以某节点为根的子树中任一节点都成为该节点的子孙。
- 森林:由m(m>0)棵互不相交的树的集合成为森林。
树的表示
孩子兄弟表示法:
struct Node {
struct Node* _firstChild1 //第一个孩子节点
struct Node* _pNextBrother //指向下一个兄弟节点
int _data //数据域
}
二叉树的概念及结构
概念
一棵二叉树是节点的一个有限集合
- 或者为空
- 由一个根节点加上两棵分别成为左子树和右子树的二叉树组成
二叉树的特点:
- 二叉树不存在度大于2的节点
- 二叉树的子树是由左右之分,次序不能颠倒,因此二叉树是有序树
特殊的二叉树
1.满二叉树
- 一个二叉树中的每一层的节点数都达到最大值,则该二叉树成为满二叉树。
- 若二叉树的层数为K,则节点总数为2^k-1。
- 满二叉树是一种特殊的完全二叉树。
2.完全二叉树
- 对于深度为K,有n个结点的二叉树·,当且仅当每一个结点从1-n每一个结点按顺序都与满二叉树相对应的称之为完全二叉树。
二叉树的性质
- 若规定根节点的层数为1,则一棵非空二叉树的 第 i 层上最多有2^(i-1)个结点.
- 若规定根节点的层数为1,则 深度为 h 的二叉树的最大结点数是2^h-1
- 对任何一棵二叉树, 如果度为 0 其叶结点个数为 , 度为 2 的分支结点个数为 , 则有 n0=n2+1
- 若规定根节点的层数为1,具有 n 个结点的满二叉树的深度, h=log2(n+1). (ps: 是log以2为底,n+1为对数)
- 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
- 若 i>0 , i 位置节点的双亲序号: (i-1)/2;i=0,i为根节点编号,无双亲节点
- 若 2i+1<n ,左孩子序号: 2i+1 , 2i+1>=n 否则无左孩子
- 若 2i+2<n ,右孩子序号: 2i+2 , 2i+2>=n 否则无右孩子
二叉树的存储结构
顺序结构
- 顺序结构是用数组进行存储,且只适合存储完全二叉树(避免空间浪费)。
- 二叉树顺序存储在物理上是一个数组,在逻辑上是一棵二叉树。
链式存储
- 用链表来表示一棵二叉树。
- 分为三个域:数据域和左右指针域
//二叉链
type BinaryTreeNode struct {
lChild *BinaryTreeNode
rChile *BinaryTreeNode
data int
}
二叉树链式结构的实现
二叉树的遍历
- 先序遍历:访问根结点在遍历其左右子树之前
- 中序遍历:访问根节点在遍历其左右子树之中
- 后序遍历:访问根节点在遍历其左右子树之后
// 先序遍历
func PrevOrder(root *BinaryTreeNode) {
if root == nil {
return
}
fmt.Printf("%d\n", root.data)
PrevOrder(root.lChild)
PrevOrder(root.rChile)
}
// 中序遍历
func InOrder(root *BinaryTreeNode) {
if root == nil {
return
}
PrevOrder(root.lChild)
fmt.Printf("%d\n", root.data)
PrevOrder(root.rChile)
}
// 后序遍历
func PostOrder(root *BinaryTreeNode) {
if root == nil {
return
}
PrevOrder(root.lChild)
PrevOrder(root.rChile)
fmt.Printf("%d\n", root.data)
}
- 层序遍历:从上到下,从左到右依次遍历即可。
哈夫曼树
给定n个值作为n个叶子结点,构造一棵二叉树,如果该树的带权路径达到最短,则该树就是哈夫曼树。
-
路径与路径长度:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。
- 通路中分支的数目称为路径长度
- 若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
-
结点的权及带权路径长度
- 定义:将树中结点赋值一个有含义的数值,则这个数值成为该结点的权。
- 结点的带权路径长度为:从根节点到该结点之间的路径场长度与该结点的权的乘积。
-
树的带权路径长度
- 定义:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL