数据结构(借鉴408)-树与二叉树
数据结构 树和二叉树
树
树的性质
存储形式
- 双亲表示法
- 孩子兄弟表示法
- 孩子链表表示法
二叉树
有序树
二叉树的性质
-
顺序存储结构 数组 一般只有完全二叉树才采用顺序结构进行存储
-
链式存储结构
//二叉树的链式存储结构
typedef struct BTNode{
ElemType data;
struct BTNode *Lchild, *Rchild;
}BTNode;
二叉树的遍历
- 先序遍历
- 中序遍历
- 后序遍历
- 层次遍历
先序遍历是入栈前访问
中序遍历是出栈之后访问
二叉树的生成:中序遍历区分左右子树,先序、后序、层次确定根
先序遍历
//递归 系统栈
void PreorderTraverse(BTNode *T){
if(T == NULL) return //访问根结点
printf(T->data);
PreorderTraverse(T->Lchild);
PreorderTraverse(T->Rchild);
}
//非递归 用户栈
中序遍历
//递归 系统栈
void inorderTraverse(BTNode *T){
if(T == NULL) return //访问根结点
inorderTraverse(T->Lchild);
printf(T->data);
inorderTraverse(T->Rchild);
}
//非递归 用户栈
后序遍历
//递归 系统栈
void postorderTraverse(BTNode *T){
if(T == NULL) return //访问根结点
postorderTraverse(T->Lchild);
postorderTraverse(T->Rchild);
printf(T->data);
}
//非递归 用户栈
层次遍历
利用队列实现
#define MAX_NODE 50
void LevelorderTraverse(BTNode *T){
BTNode *Queue[MAX_NODE], *p=T;
int front=0, rear=0;
if(p!=NULL){
Queue[rear++]=p; //根结点入队
while(front<rear){
p=Queue[front++];
visit(p->data);
if(p->Lchild != NULL)
Queue[rear++]=p->Lchild; //左结点入队
if(p->Rchild != NULL)
Queue[rear++]=p->Rchild; //右结点入队
}
}
}
线索二叉树
线索 遍历基础上,直接前驱或后继
树和二叉树的转换
树->二叉树 左孩右兄
哈夫曼树
WPL(带权路径长度)值最小的树,即哈夫曼树或最优树
构建:优先处理权值小的结点,自下向上进行构造
哈夫曼编码:左0右1
特点:
- 哈夫曼树只有0度结点和2度结点 n0=n2+1
- 哈夫曼树的WPL值最小
- 哈夫曼树不唯一,因为其左右子树可以交换,但是WPL值唯一
- 哈夫曼树本质上不属于二叉树,但考试中认为是
- 哈夫曼树的上层结点的权值不小于下层结点的权值
- 哈夫曼编码只讨论叶子的编码
平均编码长度 = WPL/(W的和)
并查集
Union-Find Sets
主要用于处理一些不相交集合的合并及查询问题
常见用途
- 求连通子图
- 求最小生成树的Kruskal算法
- 求最近公共祖先(Least Common Ancestors,LCA)
操作时间复杂度 常数级
操作:
- Make-Set(x) 建立一个新的并查集,其中包含元素x
- Union(x,y) 把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,若相交则不合并
- Find-Set(x) 找到元素x所在的集合的代表,该操作也可以用于判断两个元素是否位于同一集合,只要将它们各自的代表比较一下就可以
实现原理:树表示集合,树的每个结点表示集合中的一个元素,根对应的元素就是该集合的代表。
路径压缩:每次查找时,令查找路径上的每个结点都直接指向根结点
按秩合并:使用秩表示树高度的上界,在合并时,从事将具有较小秩大的树根指向具有较大秩的树根(将比较矮的树作为子树,添加到较高树中)
按集合中包含的元素个数(或者树中的结点数)合并,并包含结点较少的树根指向包含结点较多的树根
本文来自博客园,作者:Theseus‘Ship,转载请注明原文链接:https://www.cnblogs.com/yongchao/p/17153231.html

浙公网安备 33010602011771号