一.树的定义及基本术语
1.树的定义:
树是n(n>=0)个节点的有限集:
- 有且仅有一个特定的称之为根的节点;
- 当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1、T2、…、Tn,其中每一个集合本身又是一棵树,并且称为根的子树。
如图所示:
2.基本概念
- 节点的度:节点拥有的子树数;
- 叶子节点(终端节点):度为0的节点;
- 分支节点:度不为0的节点;
- 树的度:树内各节点度的最大值;
- 孩子:节点子树的根称为该节点的孩子,该节点称为孩子的双亲;
- 兄弟:同一双亲的节点之间互称兄弟;
- 层次:根为第0层,根的孩子为第1层,以此类推…;
- 深度:数中节点的最大层次;
- 森林:森林是m(m>=0)棵互不相交树的集合;
- 树分为有序树和无序树;
二.二叉树
1.定义
二叉树是节点的有限集合,它或者为空集,或者由一个根及两个互不相交的称为左右子树的二叉树组成。
二叉树的五种基本形态:
2.性质
- 在二叉树第i层上至多有 2 i 2^i 2i个节点(i>=0);
- 高为k(k>=0)的二叉树最多有 2 k + 1 − 1 2^{k+1}-1 2k+1−1个节点;
- 叶结点个数: n 0 n_0 n0,度为2的节点个数: n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1;
- 具有n个节点的完全二叉树的高度为 ⌊ l o g 2 n ⌋ \lfloor log_2 n\rfloor ⌊log2n⌋;
- 满二叉树:一棵深度为k且有 2 k + 1 − 1 2^{k+1}-1 2k+1−1个节点的二叉树;
- 完全二叉树:将节点从上往下,从左向右依次编号,节点的编号与满二叉树的节点的编号一一对应;
- 第 i i i个节点的左儿子的节点编号为 2 ∗ i 2*i 2∗i,右儿子为 2 ∗ i + 1 2*i+1 2∗i+1;
3.存储结构
1).顺序存储结构
用一组地址连续的存储单元依次自上而下、自左至右存储完全二叉树上的节点元素。
但这种结构仅适用于存储完全二叉树,存储其他形状的二叉树会浪费较大的空间。
#define MAX_SZIE 100
typedef TElemType SqBiTree[MAX_SIZE];
SqBiTree bt;
2).链式存储结构
节点结构如图:
lchild | Element | rchild |
---|
易证得:在含有n个节点的二叉链表中有n+1个空链域。
链式结构的存储表示:
typedef struct BiTNode{
TElemType Element;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
4.建立二叉树
void BuildBiTree(BiTree& t) {
char ch;
cin >> ch;
if (ch == ' ') {
t = NULL;
return;
}
else {
t = new BiTNode;
t->Element = ch - '0';
BuildBiTree(t->lchild);
BuildBiTree(t->rchild);
}
return;
}
5.遍历二叉树
1.) 先序遍历
递归方法:
void PreOrderBiTree(BiTree t){
if(t!=NULL){
cout<<t->Element;
PreOrderBiTree(t->lchild);
PreOrderBiTree(t->rchild);
}
}
非递归方法:
void PreOrderBiTree_non_recursion(BiTree t) {
vector<BiTNode*> stack;
BiTNode* p = t;
while (p || !stack.empty()) {
if (p) {
cout << p->Element << endl;
stack.push_back(p);
p = p->lchild;
}
else {
p = stack.back();
stack.pop_back();
p = p->rchild;
}
}
}
2).中序遍历
递归方法:
void InOrderBiTree(BiTree t) {
if (t != NULL) {
InOrderBiTree(t->lchild);
cout << t->Element << endl;
InOrderBiTree(t->rchild);
}
}
非递归方法:
void InOrderBiTree_non_recursion(BiTree t) {
vector<BiTNode*> stack;
BiTNode* p = t;
while (p || !stack.empty()) {
if (p) {
stack.push_back(p);
p = p->lchild;
}
else {
p = stack.back();
stack.pop_back();
cout << p->Element << endl;
p = p->rchild;
}
}
}
3).后序遍历
递归方法:
void PostOrderBiTree(BiTree t) {
if (t != NULL) {
PostOrderBiTree(t->lchild);
PostOrderBiTree(t->rchild);
cout << t->Element << endl;
}
}
非递归方法:
void PostOrderBiTree_non_recursion(BiTree t) {
vector<BiTNode*> stack;
BiTNode* p = t, * r = NULL;
while (p || !stack.empty()) {
if (p) {
stack.push_back(p);
p = p->lchild;
}
else {
p = stack.back();
if (p->rchild != NULL && p->rchild != r) {
p = p->rchild;
stack.push_back(p);
p = p->lchild;
}
else {
cout << p->Element << endl;
stack.pop_back();
r = p;
p = NULL;
}
}
}
}
三.线索二叉树
线索二叉树的节点结构:
lchild | LThread | val | RThread | rchild |
---|
LThread=0,代表lchild指向左儿子;
LThread=1,代表lchild指向节点的前驱;
RThread=0,代表rchild指向左儿子;
RThread=1,代表rchild指向节点的后继;
线索二叉树的存储表示:
typedef struct BiThrNode {
TElemType Element;
struct BiThrNode* lchild, * rchild;
int LThread, RThread;
}BiThrNode,*BiThrTree;
线索化二叉树:
void InThreading(BiThrTree p, BiThrNode*& pre) {
if (p) {
InThreading(p->lchild, pre);
if (p->lchild == NULL) {
p->LThread = 1;
p->lchild = pre;
}
if (pre!=NULL&&pre->rchild == NULL) {
pre->RThread = 1;
pre->rchild = p;
}
pre = p;
InThreading(p->rchild, pre);
}
}
//带头结点
void InOrderThreading(BiThrTree& Thrt, BiThrTree T) {
Thrt = new BiThrNode;
Thrt->LThread = 0, Thrt->RThread = 0;
Thrt->rchild = Thrt;
if (T == NULL) Thrt->lchild = Thrt;
else {
Thrt->lchild = T;
BiThrNode* pre = Thrt;
InThreading(T,pre);
pre->rchild = Thrt, pre->RThread = 1;
Thrt->rchild = pre;
}
}
//不带头结点
void InOrderThreading( BiThrTree &T) {
if (T != NULL)
{
BiThrNode* pre = NULL;
InThreading(T, pre);
pre->rchild = NULL, pre->RThread = 1;
}
}
四.二叉排序树
1.定义
什么是二叉排序树?
二叉排序树或者是一棵空树,或者具有如下性质的二叉树:
1. 若它的左子树不空,则左子树上所有节点的值均小于它根节点的值;
2.若它的右子树不空,则右子树上所有节点的值均大于它根节点的值;
如图所示:
2.实现
建立一个二叉排序树:
void InsertBST(BiTree &t,TElemType val){
if(t==NULL){
t=new BiTNode;
t->Element=val;
t->lchild=t->rchild=NULL;
}else if(t->Element<val){
InsertBST(t->rchild,val);
}else if(t->Element>val){
InsertBST(t->lchild,val);
}
}
####删除二叉排序树上值为val的节点:
如图所示:删除根节点
void Delete(BiTree& p){
BiTree q,s;
if(!p->rchild){
q=p,p=p->lchild;
delete q;
}else if(!p->lchild){
q=p,p=p->rchild;
delete q;
}else{
q=p,s=p->lchild;
while(s->rchild){
q=s;
s=s->rchild;
}
p->Element=s->Element;
if(q!=p){
q->rchild=s->lchild;
}else{
q->lchild=s->lchild;
}
delete s;
}
}
void DeleteBST(BiTree &t,TElemType val){
if(t==NULL) return;
else{
if(t->Element>val){
DeleteBST(t->lchild,val);
}else if(t->Element<val){
DeleteBST(t->rchild,val);
}else{
Delete(t);
}
}
}
五.平衡二叉树
1.定义
平衡二叉树又称AVL树。它或者是一棵空树,或者是具有下列性质的二叉树: 它的左子树和右子树都是平衡二叉树,且左右子树的深度之差的绝对值不超过1。
在高度为h的AVL树中,最少节点数
S
(
h
)
=
S
(
h
−
1
)
+
S
(
h
−
2
)
+
1
S(h)=S(h-1)+S(h-2)+1
S(h)=S(h−1)+S(h−2)+1;
2.实现
typedef struct AvlNode{
ElementType Element;
struct AvlNode *left,*right;
int height;
}AvlNode,*AvlTree;
3.插入(旋转操作)
在对平衡二叉树插入操作时会打破平衡,因此我们需要对二叉树进行旋转使其再次平衡。
让我们把必须重新平衡的节点叫做
a
a
a。这种不平衡可能出现在下面四种情况中:
- 对 a a a的左儿子的左子树进行一次插入;
- 对 a a a的左儿子的右子树进行一次插入;
- 对 a a a的右儿子的左子树进行一次插入;
- 对 a a a的右儿子的左子树进行一次插入;
第一种情况和第四种情况通过对树的一次单旋转而完成调整;第二种和第三种情况通过对树的一次双旋转来处理。
单旋转
情形1:对k2的左儿子的左子树进行一次插入;
实现:
AvlNode* SingleRotateWithLeft(AvlNode* k2){
AvlNode *k1;
k1=k2->left;
k2->left=k1->right;
k1->right=k2;
k2->height=max(height(k2->left),height(k2->right))+1;
k1->height=max(height(k1->left),k2->height)+1;
return k1;
}
情形4:对k1的右儿子的右子树进行一次插入;
实现:
AvlNode* SingleRotateWithRight(AvlNode* k1){
AvlNode *k2;
k2=k1->right;
k1->right=k2->left;
k2->left=k1;
k1->height=max(height(k1->left),height(k1->right))+1;
k2->height=max(k1->height,height(k2->right))+1;
return k1;
}
双旋转
情形2: 对k3的左儿子的右子树进行一次插入;
实现:
AvlTree_Position DoubleRotateWithLeft(AvlTree K3){
K3->lchild=SingleRotateWithRight(K3->lchild);
return SingleRotateWithLeft(K3);
}
情形3:对k3的右儿子的左子树进行一次插入;
实现:
AvlTree_Position DoubleRotateWithRight(AvlTree K3){
K3->rchild=SingleRotateWithLeft(K3->rchild);
return SingleRotateWithRight(K3);
}
向平衡二叉树中插入一个节点:
AvlTree_Position AvlTree_Insert(AvlTreeElementType X,AvlTree T){
if(T==NULL){
T=new AvlTreeNode;
T->Element=X;
T->height=0;
T->lchild=T->rchild=NULL;
return T;
}else if(X<T->Element){
T->lchild=AvlTree_Insert(X,T->lchild);
if(abs(AvlTree_Height(T->lchild))-AvlTree_Height(T->rchild)>1){
if(X<T->lchild->Element){
T=SingleRotateWithLeft(T);
}else{
T=DoubleRotateWithLeft(T);
}
}
}else if(X>T->Element){
T->rchild=AvlTree_Insert(X,T->rchild);
if(abs(AvlTree_Height(T->lchild)-AvlTree_Height(T->rchild))>1){
if(X>T->rchild->Element){
T=SingleRotateWithRight(T);
}else{
T=DoubleRotateWithRight(T);
}
}
}
T->height=max(AvlTree_Height(T->lchild),AvlTree_Height(T->rchild))+1;
return T;
}
六.HuffmanTree
关于HuffmanTree,我参考了CSDN中的文章。https://blog.csdn.net/qq_29542611/article/details/79334308