树和森林:
树:有且只有一个根节点,其余节点互不相交。
森林:是M棵树互不相交的树的集合。
树的存储方式:
1.双亲表示法:
定义结构数组,里面有一个数据域和一个双亲域,用数组下标记录节点位子,然后用双亲域记录父节点的下标在哪。
特点:找双亲容易,找孩子难
2.孩子链表:
方法:把每个节点的的孩子结点排列起来,看成是一个线性表连接。然后用一个数组把他们头结点记录下来,每个头结点里面可以看到他们的还在结点在那个位置。然后用数组下表记录结点位置。
特点:找孩子容易,找双亲难
优化下:在数组中加入记录双亲的结点
3.孩子兄弟表示法:
实现:用二叉链表做树的存储结构,链表中每个结点有两个指针域,一个指向第一个孩子结点一个指向兄弟结点,就是左孩子右兄弟表示一颗树。
typedef strcut CSNode{
ElemType Data;
struct CSNode * FirstChild,NextSibling;
}CSNode,*CSTree;
树和二叉树的转换:
给定一个树可以找到唯一一颗对应的二叉树,因为树的孩子兄弟表示法。
将树转为二叉树:
- 加线:在兄弟之间加上连线。
- 去线:对于每个结点,除了左孩子外,去除其与其余孩子之间的关系。就是去掉双亲的线
- 旋转:以树根为轴心,顺时针旋转45°。
树变二叉树口诀:兄弟相连留长子。
将二叉树变为树:
- 加线:若结点P是双亲结点的左孩子,则将P的右孩子,右孩子的右孩子。。。。。。沿着分支找到所的右孩子,都与P的双亲用线连起来。
- 去线:去除原二叉树中双亲与右孩子之间的连线。
- 调整:将节点按层次排列,形成树结构。
二叉树变树口诀:左孩右右连双亲,去掉原来右孩线。
森林和二叉树的转换:
将森林变为二叉树:
涉及到二叉树和多棵树的关系,实现方法:
- 将各课树分别转成二叉树
- 每棵树的根节点用线相连
- 以第一颗树的根节点为二叉树的根,再以根节点为轴心顺时针旋转。
森林变二叉树口诀:树变二叉根相连
将二叉树变成森林:
- 去线:将二叉树中根节点与其右孩子相连,及沿着右分支搜索到的所有右孩子之间的连线全部出去,使之成为一颗孤立的二叉树
- 还原:再将孤立的二叉树还原成树
二叉树变森林口诀:去掉全部右孩线,孤立二叉再还原
树和森林的遍历
树的遍历(三种方式):
- 先根遍历:先访问根节点再按照先根的方式遍历各棵子树
- 后根遍历:从后往前,从左到右的次序遍历节点,直到访问到根节点为止。
- 层次遍历:从上到下从左到右访问每个节点
森林的遍历:
遍历方式:
- 先序遍历:将森林中的树从左到右,每一棵树按照树的先序遍历的方式去遍历
- 中序遍历:将森林中的树从左到右,每一棵按照树的后序遍历的方式去遍历
堆(优先队列):
堆是特殊的队列,从队中取出元素是依照元素的优先级大小进行的。
堆的两个特性:
- 结构性:用数组表示的完全二叉树
- 有序性:任何一结点元素的数值与其子节点存储的值是相关的
最大堆:任一结点的值大于或等于其子结点的值。
最小堆:任一结点的值小于或等于其子节点的值。
堆中的元素在数组中是按完全二叉树的层序储存的,根节点存放在数组的起始处,接着是其子节点,一层一层下去到最后一个节点。注意,所用的数组起始单元为1,这样做的目的是从子节点容易找到父节点。
根据二叉树顺序存储二叉树的性质,对于下标为i的结点,其父节点的下标为i/2。而反过来,找第i个结点的左右节点,左节点为2i,右节点为2i-1。
堆的调整:
输出堆顶元素后,用最后一个位置的元素去顶替他,然后从堆顶开始排序,如果是最大堆,进行的就是比较左右树和最大的交换,然后沿着交换的方向进行,一直到叶节点为止。
堆的建立:
就是对于一个下标从一开始的数组所表示的完全二叉树,我们记他的结点数为N,对于建立一个堆就是从最后一个非叶子结点开始跳针,位置是N/2,