04树和二叉树

213 阅读4分钟

一、二叉树的性质

性质1:在二叉树的第i层上至多有 **2^(i-1)**个结点(i>=1)

性质2:深度为k的二叉树至多有2^(k)-1个结点(k>=1)

性质3:n0 = n2 + 1

性质4:具有n个结点的完全二叉树的深度是floor(log2 n)+1

性质5:完全二叉树中,已知结点为i,则双亲结点为floor(i / 2)

已知结点为i,左结点为2i,右结点为2i+1

二、二叉树的顺序存储

#define MAXSIZE 100
typedef int TElemType;
typedef TElemType SqBiTree[MAXSIZE];
SqBiTree bt;

三、二叉树的二叉链表存储表示

typedef struct BiTNode {
	TElemType data;
	struct BiTNode *lchild, *rchild;
} BiTNode,*BiTree;

四、二叉树的遍历

1.中序遍历

void InOrderTraverse(BiTree T) {
	// 中序遍历二叉树T的递归算法
	if(T) {
		InOrderTraverse(T->lchild);		// 左 
		cout << T->data;				// 根 
		InOrderTraverse(T->lchild);		// 右 
	} 
}

2.前序遍历

void PreOrderTraverse(BiTree T) {
	// 前序遍历二叉树T的递归算法
	if(T) {
		cout << T->data;					// 根
		PreOrderTraverse(T->lchild);		// 左 
		PreOrderTraverse(T->lchild);		// 右 
	} 
} 

3.后序遍历

void PostOrderTraverse(BiTree T) {
	// 后序遍历二叉树T的递归算法
	if(T) {
		PostOrderTraverse(T->lchild);		// 左 
		PostOrderTraverse(T->lchild);		// 右
		cout << T->data;					// 根 
	} 
} 

4.二叉树的还原

有两种方式还原二叉树:

1.已知前序和中序

2.已知中序和后序

3.注意:已知前序和后序无法还原,上面的知二推一

还原第一步先找到根节点

可以通过找到前序的第一个结点后序的最后一个结点

接下来去中序找这个根节点,左边就是左子树,右边就是右子树

然后回到前或后序列,分别找到左右子树所在位置,接下来同上

再找到左子树和右子树的根节点,再回中序,以此类推。。。

五、二叉树的创建

void CreateBiTree(BiTree &T) {
	// 按前序次序输入二叉树中节点的值(一个字符),创建二叉链表表示的二叉树T
	char ch;
	cin >> ch;
	if(ch == '#') T = NULL;		// 递归结束,创建空树
	else {
		T = (BiTree)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	} 
}

六、复制二叉树

void Copy(BiTree T, BiTree &NewT) {
	// 复制一棵和T完全相同的二叉树
	if(T == NULL) {
		NewT = NULL;
		return;
	} else {
		NewT = (BiTree)malloc(sizeof(BiTNode));
		NewT->data = T->data;
		Copy(T->lchild, NewT->lchild);		// 递归复制左子树 
		Copy(T->rchild, NewT->rchild);		// 递归复制右子树 
	}

}

七、计算二叉树的深度

int Depth(BiTree T) {
	if(T == NULL) return 0;
	else {
		int m = Depth(T->lchild);		// 左右子树深度分别是m,n 
		int n = Depth(T->rchild);
		if(m > n) return (m+1);
		else return (n+1); 
	}
}

八、统计二叉树中结点的个数

int NodeCount(BiTree T) {
	// 统计二叉树T中结点的个数
	if(T == NULL) return 0;
	else {
		return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;	// +1是根节点 
	} 
}

九、森林与二叉树的转换

1.树转换成二叉树

1.加线。在所有兄弟结点之间加一条线(横向全部连着)

2.去线。对每个结点,只保留第一个孩子的连线,其他孩子的线全部断掉

3.层次调整。以树的根结点为轴心,将整棵树顺时针旋转。
要注意第一个孩子是二叉树结点的左孩子,
兄弟转换过来是二叉树结点的右孩子。

2.森林转换为二叉树

1.把每棵树都转换为二叉树(上面的方法)

2.第一棵树不动,第二棵树开始,后一棵树的根结点作为前一棵树的右孩子
也就是说第二棵树的根结点作为第一棵树的右孩子,后面的以此类推。

3.二叉树转换为树

1.加线。如果某结点有左孩子,则把左孩子的右孩子,或左孩子的右孩子的右孩子的....
与当前结点相连。

2.去线。删除原二叉树中所有结点与其右孩子结点的连线。

3.层次调整。做一个简单的逆时针旋转,让所有结点能按照层次排列。

十、赫夫曼树

1.根据给定的n个权值{W1,W2,...,Wn}构成n棵二叉树的集合F={T1,T2,...Tn},
其中每棵二叉树 Ti 中只有一个带权 Wi 根结点,其左右子树均为空。

2.在F中选取两棵根节点的权值最小的树作为左右子树构造一棵新的二叉树,且
置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。小的作为左孩子,大的为右孩子

3.在F中删除这两棵树,同时将新得到的二叉树加入F中。

4.重复2 和 3步骤,直到F只含一棵树为止。这棵树便是赫夫曼树。

赫夫曼编码

设需要编码的字符集为{d1,d2,...,dn},各个字符在电文中出现的次数或频率
集合为{w1,w2,...,wn},以d1,d2,...,dn作为叶子结点,以w1,w2,...,wn作
为相应叶子结点的权值来构造一棵赫夫曼树。规定赫夫曼树的左分支代表0,
右分支代表1,则从根节点到叶子结点所经过的路径分支组成的0和1的序列便为该节点
对应字符的编码,成为赫夫曼编码。