树
概念
树(Tree)是n(n>=0)个节点的有限集合 T,它满足两个条件:
1)有且仅有一个特定的称为根(Root)的节点;
2)其余的节点可以分为m(m≥0)个互不相交的有限集合 T1、T2、……、Tm,
其中每一个集合又是一棵树,并称为其根的子树(Subtree)。

特征
一对多,每个节点最多有一个前驱,但可以有多个后继(根节点无前驱,叶节点无后继)。
名词解释
度数:
一个节点的子树的个数(一个节点的子树的个数称为该节点的度数)。
树 的度数:
树中节点的最大度数。
叶节点 或 终端节点:
度数为零的节点 。
分支节点 = 根节点 + 内部节点
度数不为零的节点。
内部节点:
除根节点以外的分支节点 (B,C,D,E,H)。
节点层次:
根节点的层次为1,根节点子树的根为第2层,以此类推。
树的深度或高度:
树中所有节点层次的最大值。

二叉树
二叉树(Binary Tree)是 n(n≥0)个节点的有限集合,它或者是空集(n=0),
或者是由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成。
二叉树严格区分左孩子和右孩子,即使只有一个子节点也要区分左右。

满二叉树
深度为k(k>=1)时节点为2^k - 1。

完全二叉树
只有最下面两层有 度数小于2 的节点,且最下面一层的叶节点集中在最左边的若干位置上。

性质
1、二叉树第 k(k>=1)层上 最多有 2^(k-1) 个节点;
2、深度为 k(k>=1)的二叉树 最多有 2^k-1 个节点;
3、在任意一棵二叉树中,树叶的数目比度数为2的节点的数目多一。
总节点数 n = n0 + n1 + n2
总节点数 n = 子节点总数 + 1
子节点总数 = n1 + 2n2
∴ n0 = n2 + 1
最优二叉树(赫夫曼树)
给定 N 个权值作为 N 个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
路径、路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第 L 层结点的路径长度为 L-1。
结点的权、带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
树的带权路径长度(WPL)
树的带权路径长度规定为所有叶子结点的带权路径长度之和,
记为WPL(Weighted Path Length of Tree)。
e.g.

而,WPLmin = 71 + 22 + 5*2 = 21.
节点编号
完全二叉树节点的编号方法:从上到下,从左到右,根节点为1号节点。
根节点:编号 1
根节点左子节点编号: 2
根节点右子节点编号: 3
……
第 i 个节点
左子节点编号: 2 * i
右子节点编号: 2 * i + 1
有无父子节点的判定
设完全二叉树的节点数为 n,某节点编号为 i:
当 i >1(不是根节点)时,有父节点,其父节点编号为 i / 2;
当 2i <= n 时,有左孩子,其编号为 2i (否则没有左孩子,本身是叶节点);
当 2i+1 <=n 时,有右孩子,其编号为 2i+1 (否则没有右孩子)。
二叉树的顺序存储结构
存储
有 n 个节点的完全二叉树可以用有 n+1 个元素的数组进行顺序存储,节点号和数组下标一一对应,
下标为零的元素不用。
利用以上特性,可以从下标获得节点的逻辑关系。
不完全二叉树通过添加虚节点构成完全二叉树,采用数组存储会浪费一些存储空间。

遍历
前序:根 ----> 左 -----> 右
中序:左 ----> 根 -----> 右
后序:左 ----> 右 -----> 根
e.g.

前序:
A —> B —> C —> D —> E —> F —> G —> H —> K
中序:
B —> D —> C —> A —> E —> H —> G —> K —> F
后序:
D —> C —> B —> H —> K —> G —> F —> E —> A
e.g.
已知遍历结果如下,试画出对应的二叉树:
前序: A B C E H F I J D G K
中序: A H E C I F J B D K G

二叉树的链式存储
层次遍历(队列思想)





bitree.h
#ifndef _BITREE_H_
#define _BITREE_H_
typedef char datatype_tree;
typedef struct tree_node_t
{
datatype_tree data; // 数据域
struct tree_node_t *lchild; // 左子left
struct tree_node_t *rchild; // 右子right
}bitree_node_t, *bitree_list_t;
// 创建
bitree_list_t CreateBitree(int n,int i);
// 前序
void PreOrder(bitree_list_t r);
// 中序
void InOrder(bitree_list_t r);
// 后序
void PostOrder(bitree_list_t r);
// 释放
void Delete(bitree_list_t r);
#endif
makefile
CC=gcc
OBJS=main.o create.o pre_in_post_order.o delete.o
CFLAGS=-c -Wall -g -o
bitree:$(OBJS)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGS) $@ $<
.PHONY:clean
clean:
rm *.o seqlist -f
main.c
#include <stdio.h>
#include "bitree.h"
int main(int argc, char const *argv[])
{
printf("Please input 'n' for the number of bitree nodes: ");
int n;
scanf("%d", &n);
bitree_list_t root = CreateBitree(n, 1);
PreOrder(root);
putchar(10);
InOrder(root);
putchar(10);
PostOrder(root);
putchar(10);
Delete(root);
return 0;
}
*.c
/***********************************************************/
// create.c
#include <stdio.h>
#include <stdlib.h>
#include "bitree.h"
// 创建
bitree_list_t CreateBitree(int n, int i){
bitree_list_t current_root = (bitree_list_t)malloc(sizeof(bitree_node_t));
if (current_root == NULL){
perror("Failed to create a root.");
return NULL;
}
current_root->data = i + 64;
if (2*i <= n)
current_root->lchild = CreateBitree(n, 2*i);
else
current_root->lchild = NULL;
if (2*i+1 <= n)
current_root->rchild = CreateBitree(n, 2*i+1);
else
current_root->rchild = NULL;
return current_root;
}
/***********************************************************/
// delete.c
#include <stdio.h>
#include <stdlib.h>
#include "bitree.h"
// 释放
void Delete(bitree_list_t r){
if (r == NULL)
return;
Delete(r->lchild);
Delete(r->rchild);
free(r);
r = NULL;
}
/***********************************************************/
// pre_in_post_order.c
#include <stdio.h>
#include "bitree.h"
// 前序
void PreOrder(bitree_list_t r){
if (r == NULL)
return;
printf("%c ", r->data);
PreOrder(r->lchild);
PreOrder(r->rchild);
}
// 中序
void InOrder(bitree_list_t r){
if (r == NULL)
return;
InOrder(r->lchild);
printf("%c ", r->data);
InOrder(r->rchild);
}
// 后序
void PostOrder(bitree_list_t r){
if (r == NULL)
return;
PostOrder(r->lchild);
PostOrder(r->rchild);
printf("%c ", r->data);
}
/***********************************************************/
实现效果

本文详细介绍了树的概念,包括树的定义、特征、度数、节点分类,以及二叉树、满二叉树、完全二叉树的特性和性质。重点讲解了最优二叉树(哈夫曼树)和带权路径长度的概念,以及节点编号规则和二叉树的三种遍历方式(前序、中序、后序)。同时给出了C语言代码示例实现树的创建、遍历和释放操作。
9079

被折叠的 条评论
为什么被折叠?



