1、
树(不包含回路的,即n个结点恰好有n-1条边)
任意两个结点有且仅有唯一的一条路径连通。
根/祖先/根节点(没有父亲)
节点/结点
夫节点/父亲
子节点/儿子
叶结点(没有儿子)
深度:根到这个结点的层数。
2、 二叉树:每个结点最多有两个儿子(左儿子,右儿子)
满二叉树:每个结点都有两个儿子/所有的叶结点都有相同的深度。
深度为h且有2^h-1个结点的二叉树。
完全二叉树:满二叉树最右边位置上拿掉一个或者几个叶结点
深度为h,除h层外,其他各层(1 - h-1)的结点数都达到最大个数。
完全二叉树存储:一维数组,从左到右一层一层放。
有N个结点,那么这个完全二叉树的高度为log 2 N。
最典型的应用就是堆。
3、 最小堆:所有父结点都比子结点要小
随便n元素的数,按照完全二叉树方式放入一个数组,生成最小堆:
1、从最后一个非叶结点(结点数组编号为n/2)开始,对该结点和下面的左右叶结点进行比较,使最小的数放在非叶结点上。
2、扫描完这层后,开始扫描上一层,该结点如果要移位,就需要对下面及下面的叶结点进行比较,使其符合最小堆要求,不移位不比较。
3、重复,直到扫描到根节点(结点编号为1)为止。
时间复杂度O(N)
5、 堆排序
时间复杂度和快速排序一样O(NlogN)。
以从小到大排序为例。
1、生成最大堆
2、把数组中最后h[n]的数和h[1]的数进行交换,n--
3、补上来的数h[1]和子节点一层一层对比,把小的数往上移,直到不能移动时,再跳到2反复。
create();
while(n>1)
{
swap(1,n);
n--;
siftdown(1);
}
siftdown(int i)
{
while(!到底或已经没有小的)
{
n[i]和左儿子比,和右儿子比,如果有小的交换并记录在t中。
更新到交换后的结点i=t。
}
}
6、 堆的应用
优先队列:普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。
二叉堆就是优先队列(父节点大于子节点)
求一个数列中第K大/小的数。
取出K个数建一个大小为K的最小/大堆,再从K+1个数开始,依次拿去和堆顶比较,如果要小/大,就舍弃,如果大/小就一层一层往下比和移。
时间复杂度O(NlogN)
并查集/不相交集数据结构的算法:
通过一个数组来实现,其本质是维护一个森林,刚开始的时候,森林的每个点都是孤立的,可理解成一个结点的树,
之后通过一些条件,逐步将这些树合并成一棵大树。判断两个节点是否已经在同一棵树(数其实是个集合)中的时候,
也要注意必须求其根源,中间父亲节点是不能说明问题的,必须找到其祖宗判断两个结点的祖宗是否是同一个根结点才行。
任意两个结点有且仅有唯一的一条路径连通。
根/祖先/根节点(没有父亲)
节点/结点
夫节点/父亲
子节点/儿子
叶结点(没有儿子)
深度:根到这个结点的层数。
2、 二叉树:每个结点最多有两个儿子(左儿子,右儿子)
满二叉树:每个结点都有两个儿子/所有的叶结点都有相同的深度。
深度为h且有2^h-1个结点的二叉树。
完全二叉树:满二叉树最右边位置上拿掉一个或者几个叶结点
深度为h,除h层外,其他各层(1 - h-1)的结点数都达到最大个数。
完全二叉树存储:一维数组,从左到右一层一层放。
有N个结点,那么这个完全二叉树的高度为log 2 N。
最典型的应用就是堆。
3、 最小堆:所有父结点都比子结点要小
随便n元素的数,按照完全二叉树方式放入一个数组,生成最小堆:
1、从最后一个非叶结点(结点数组编号为n/2)开始,对该结点和下面的左右叶结点进行比较,使最小的数放在非叶结点上。
2、扫描完这层后,开始扫描上一层,该结点如果要移位,就需要对下面及下面的叶结点进行比较,使其符合最小堆要求,不移位不比较。
3、重复,直到扫描到根节点(结点编号为1)为止。
时间复杂度O(N)
5、 堆排序
时间复杂度和快速排序一样O(NlogN)。
以从小到大排序为例。
1、生成最大堆
2、把数组中最后h[n]的数和h[1]的数进行交换,n--
3、补上来的数h[1]和子节点一层一层对比,把小的数往上移,直到不能移动时,再跳到2反复。
create();
while(n>1)
{
swap(1,n);
n--;
siftdown(1);
}
siftdown(int i)
{
while(!到底或已经没有小的)
{
n[i]和左儿子比,和右儿子比,如果有小的交换并记录在t中。
更新到交换后的结点i=t。
}
}
6、 堆的应用
优先队列:普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。
二叉堆就是优先队列(父节点大于子节点)
求一个数列中第K大/小的数。
取出K个数建一个大小为K的最小/大堆,再从K+1个数开始,依次拿去和堆顶比较,如果要小/大,就舍弃,如果大/小就一层一层往下比和移。
时间复杂度O(NlogN)
并查集/不相交集数据结构的算法:
通过一个数组来实现,其本质是维护一个森林,刚开始的时候,森林的每个点都是孤立的,可理解成一个结点的树,
之后通过一些条件,逐步将这些树合并成一棵大树。判断两个节点是否已经在同一棵树(数其实是个集合)中的时候,
也要注意必须求其根源,中间父亲节点是不能说明问题的,必须找到其祖宗判断两个结点的祖宗是否是同一个根结点才行。