#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<queue>
#define ElemType int
#define MaxSize 100
using namespace std;
/*树的基本概念
空树-结点数为0的树(森林也有空森林)
非空树:
1.有且仅有一个根结点;
2.没有后继的结点称为“叶子结点(终端结点)”;
3.有后继的结点称为“分支结点(非终端结点)”;
4.除了根结点,每个结点都有且仅有一个前驱,可以有0个或多个后继。
!树是一种递归定义的数据结构
!祖先结点->从一个结点走到根结点经过的所有结点
!数的路径只能从小往下走
!结点的高度->从下往上数 !注意是高度,不是深度/层次!
*/
/*树的性质
1.结点数=总度数+1
2.度为m的树:结点最多有m个孩子,最少存在1个有m个孩子的结点,一定是非空树(至少有m+1个结点)
3.m叉树:结点最多有m个孩子,允许所有结点度<m,可以是空树
4.度为m的树和m叉树第i层都至多有m^(i-1)个结点,高度为h时,至多有m^h-1 / m-1 个结点
5.高度为h的m叉树至少有h个结点,度为m的树至少有h+m-1个结点
!6.具有n个结点的m叉树的最小高度为 logm(n(m-1)+1)向上取整 h-1<logm(n(m-1)+1)<=h
*/
/*树的遍历
先根遍历=二叉树先序遍历
后根遍历=二叉树中序遍历
层次遍历
*/
/*森林的遍历
先序遍历=依次对子树先根遍历
中序遍历=依次对子树后根遍历
*/
/*二叉树的基本概念(可以是空二叉树)
注意:左右子树不能颠倒,是有序树
!满二叉树:结点数一定等于2^h-1
只有最后一层有叶子结点!不存在度为1的结点!
!左孩子编号是2i,右孩子是2i+1,父节点如果有就是i/2
!完全二叉树:结点编号与满二叉树一一对应(空树是)
只有最后两层有叶子结点!最多只有一个度为1的结点->!所有如果存在一个结点有一个孩子,一定是左孩子!
!如果结点存在,则编号规则同上
!编号<=n/2为分支结点,i>n/2为叶子结点
!二叉排序树:(可以空)
!平衡二叉树:任何一个结点的左右子树深度之差不超过1的二叉排序数
*/
/*二叉树的性质
1.非空二叉树中,n0=n2+1,即叶子结点比二分支结点多一个
2.第i层最多有多少个结点
3.高度为h的二叉树最多有多少个结点
完全二叉树的高度为 log2(n+1)向上取整 or log2n向下取整+1
完全二叉树n1=0或1,n0+n2一定是奇数!!!
*/
//二叉树的顺序存储->只适合存储完全二叉树
struct TreeNode {
ElemType data;
bool isEmpty;
};
TreeNode t[MaxSize];//t[0]空缺,需要初始化所有的isEmpty
//二叉树的链式存储 有2n的指针域,其中n+1为空指针域(只有左右孩子指针时)
typedef struct BiTNode {
ElemType data;
struct BiTNode *lchild, *rchild;
struct BiTNode *parent;
int ltag, rtag;
}BiTNode, *BiTree, ThreadNode, *ThreadTree;
BiTree T = NULL;
//先序遍历
void PreOrder(BiTree T) {
if (T != NULL) {
printf("%d\t", T->data);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//中序遍历
void InOrder(BiTree T) {
if (T != NULL) {
InOrder(T->lchild);
printf("%d\t", T->data);
InOrder(T->rchild);
}
}
//后序遍历
void PostOrder(BiTree T) {
if (T != NULL) {
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%d\t", T->data);
}
}
//求树的深度
int treeDepth(BiTree T) {
if (T == NULL) return 0;
int l = treeDepth(T->lchild);
int r = treeDepth(T->rchild);
return l > r ? l + 1 : r + 1;
}
//层序遍历
void LevelOrder(BiTree T) {
queue<BiTNode*> q;
if (T != NULL) {
printf("%d\t", T->data);
q.push(T);
}
while (!q.empty()) {
BiTNode* t = q.front();
q.pop();
if (t->lchild != NULL) {
printf("%d\t", t->lchild->data);
q.push(t->lchild);
}
if (t->rchild != NULL) {
printf("%d\t", t->rchild->data);
q.push(t->rchild);
}
}
}
//中序线索化
ThreadNode *pre = NULL;
void visit(ThreadNode *q) {
if (q->lchild == NULL) {
q->lchild = pre;
q->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = q;
pre->rtag = 1;
}
pre = q;
}
void InThread(ThreadTree T) {
if (T != NULL) {
InThread(T->lchild);
visit(T);
InThread(T->rchild);
}
}
void CreateInThread(ThreadTree T) {
pre = NULL;
if (T != NULL) {//必须判断!如果为空就不存在pre->rchild
InThread(T);
if (pre->rchild == NULL)
pre->rtag = 1;
}
}
//先序线索化
void PreThread(ThreadTree T) {
if (T != NULL) {
visit(T);
if (T->ltag == 0)//!!!注意!!!
PreThread(T->lchild);
if (T->rtag == 0)
PreThread(T->rchild);
}
}
void CreatePreThread(ThreadTree T) {
pre = NULL;
if (T != NULL) {
PreThread(T);
if (pre->rchild == NULL)
pre->rtag = 1;
}
}
//后序线索化
void PostThread(ThreadTree T) {
if (T != NULL) {
PostThread(T->lchild);
PostThread(T->rchild);
visit(T);
}
}
void CreatePostThread(ThreadTree T) {
pre = NULL;
if (T != NULL) {
PostThread(T);
if (pre->rchild == NULL)//只有后序不可以省略
pre->rtag = 1;
}
}
//输出中序线索二叉树
void OutInThread(ThreadTree T) {
if (T == NULL)return;
while (T->ltag == 0)
T = T->lchild;
while (T != NULL) {//注意是T不是T的孩子!
printf("%d\t", T->data);
if (T->rtag == 1)
T = T->rchild;
else {
T = T->rchild;
while (T->ltag == 0)
T = T->lchild;
}
}
}
//逆序输出中序线索二叉树
void ReOutInThread(ThreadTree T) {
if (T == NULL)return;
while (T->rtag == 0)
T = T->rchild;
while (T != NULL) {
printf("%d\t", T->data);
if (T->ltag == 1)
T = T->lchild;
else {
T = T->lchild;
while (T->rtag == 0)
T = T->rchild;
}
}
}
//输出先序线索二叉树
void OutPreThread(ThreadTree T) {
while (T != NULL) {
printf("%d\t", T->data);
if (T->rtag == 1)
T = T->rchild;
else {
if (T->ltag == 0) {
T = T->lchild;
}
else
T = T->rchild;
}
}
}
//根据父节点逆序输出先序线索二叉树
void ReOutPreThread(ThreadTree T) {
if (T == NULL)return;
while (T->ltag == 0 || T->rtag == 0) {
if (T->rtag == 0)
T = T->rchild;
else if (T->ltag == 0)
T = T->lchild;
}
while (T != NULL) {
printf("%d\t", T->data);
ThreadNode *q = T; _abs64
}
}
//根据父节点输出后序线索二叉树
void OutPostThread(ThreadTree T) {
if (T == NULL)return;
while (T->ltag == 0 || T->rtag == 0) {
if (T->ltag == 0)
T = T->lchild;
else if (T->rtag == 0)
T = T->rchild;
}
while (T != NULL) {
printf("%d\t", T->data);
ThreadNode *q = T;
T = T->parent;
if (T != NULL && T->ltag == 0 && q == T->lchild&&T->rtag == 0) {
T = T->rchild;
while (T->ltag == 0 || T->rtag == 0) {
if (T->ltag == 0)
T = T->lchild;
else if (T->rtag == 0)
T = T->rchild;
}
}
}
}
//逆序输出后序线索二叉树
void ReOutPostThread(ThreadTree T) {
while (T != NULL) {
printf("%d\t", T->data);
if (T->ltag == 1)
T = T->lchild;
else {
if (T->rtag == 0)
T = T->rchild;
else
T = T->lchild;
}
}
}
//根据A[]创建二叉排序树
void CreateBST(BiTree &T, int A[], int n) {
if (n > 0) {
BiTNode *q = (BiTNode*)malloc(sizeof(BiTNode));
q->data = A[0];
q->lchild = q->rchild = q->parent = NULL;
q->ltag = q->rtag = 0;
T = q;
}
for (int i = 1; i < n; i++) {
BiTree t = T;
while (1) {
if (A[i] > t->data) {
if (t->rchild != NULL)
t = t->rchild;
else {
BiTNode *q = (BiTNode*)malloc(sizeof(BiTNode));
q->data = A[i];
q->lchild = q->rchild = NULL;
q->ltag = q->rtag = 0;
t->rchild = q;
q->parent = t;
break;
}
}
if (A[i] < t->data) {
if (t->lchild != NULL)
t = t->lchild;
else {
BiTNode *q = (BiTNode*)malloc(sizeof(BiTNode));
q->data = A[i];
q->lchild = q->rchild = NULL;
q->ltag = q->rtag = 0;
t->lchild = q;
q->parent = t;
break;
}
}
}
}
}
/*哈夫曼树
结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积
树的带权路径长度:树中所有叶结点的带权路径长度之和(WPL,Weighted Path Length)
哈夫曼树(最优二叉树):在含有n个带权叶结点的二叉树中,其中带权路劲长度(WPL)最小的二叉树
哈夫曼树的结点总数为2n-1,且并不存在度为1的结点
固定长度编码-每个字符用相等长度的二进制位表示
可变长度编码-允许对不同字符用不等长的二进制位表示
前缀编码-没有一个编码是另一个编码的前缀
*/
int main() {
int A[] = { 16,8,32,1024,4,128,64,512,0,2,256 };
int n = sizeof(A) / sizeof(A[0]);
CreateBST(T, A, n);
PreOrder(T); printf("前序遍历\n");
InOrder(T); printf("中序遍历\n");
PostOrder(T); printf("后序遍历\n");
LevelOrder(T); printf("层次遍历\n");
printf("树高:%d\n", treeDepth(T));
printf("正在中序线索化……\n");
CreateInThread(T);
OutInThread(T); printf("输出中序线索二叉树\n");
ReOutInThread(T); printf("逆序输出中序线索二叉树\n");
T = NULL; CreateBST(T, A, n);
printf("正在先序线索化……\n");
CreatePreThread(T);
OutPreThread(T); printf("输出先序线索二叉树\n");
ReOutPreThread(T); printf("逆序输出先序线索二叉树\n");
T = NULL; CreateBST(T, A, n);
printf("正在后序线索化……\n");
CreatePostThread(T);
OutPostThread(T); printf("输出后序线索二叉树\n");
ReOutPostThread(T); printf("逆序输出先序线索二叉树\n");
return 0;
}
关于树及其操作
最新推荐文章于 2024-07-12 16:27:59 发布