开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第27天,点击查看活动详情
学到树时候,是不是大家有这个疑问:树和图有什么不一样的吗?因为树很像无向图,树其实是不包含回路的联通无向图。因为他不包含回路,所以一棵树的任意两个节点有且仅有唯一的一条路径联通,如果一个树有n个节点,那么他一定有n-1个边,在一个树里面加一条边就会变成回路
二叉树
特点:每个节点最多有两个儿子,或者说一个节点最多有两棵子树。更严格定义是:二叉树要么为null要么由根节点,左、右子树构成。
满二叉树:一棵深度为h,且有2^h-1个节点的二叉树。
如果一棵二叉树除了最右边位置上有一个或者几个叶节点缺失,其他是满的,那么这样二叉树叫完全二叉树。严格定义:若二叉树高度为h,除了第h层歪,其他各层节点都是最大个数,从第h层从右向左连续缺失若干节点,则这个二叉树就是完全二叉树。也就是说,如果一个节点有右节点,那么一定有左节点。
一个完全二叉树要怎么存储呢?我们可以使用一个一维数组,把二叉树按照从上到下,从左到右编号
从图中可以看出来:如果父节点为k那么左儿子就是2k,右儿子就是2k-1,已知子节点为k那么父节点就是k/2,如果一个树有N个节点,那么这个树高度为:
二叉树最典型应用就是堆。
堆分最大堆(父节点大于所有子节点),最小堆(父节点小于所有子节点)
假设有14个数,我们怎么删除他的最小值?方法有很多,最简单就是循环扫描一遍。那么在这个基础上,再次新增一个数,然后再次删除最小值该怎么完成?
或许你会说,把第一个找到的最小值和加入数比较,如果比最小值小,再次删除最小就是删除新加的,如果不是把数组再扫描一次,找到最小值,删除。可是这样时间复杂度是O(14)或者O(14^2)。在这种情况下,我们最好是使用最小堆
这是一个最小堆,删除最小值,其实就是删除堆顶部元素,如果新添加23,把23放在堆顶部,这个时候肯定不符合最小堆,那么进行调整
到这里,最小堆就调整完成了
那么代码如何实现?
我们可以使用 PriorityQueue 类在 Java 中实现堆。该类默认实现了最小堆,我们可以使用 Collections 中的 reverseOrder() 方法来实现最大堆。我们可以使用 peek() 方法来显示堆中根节点的元素。poll() 方法返回并删除根节点的值。我们可以使用 contains() 方法来检查元素是否存在于堆中。
。。。
//1,默认实现的是最小堆,元素按照natural ordering排序(自然排序,例如,数字的从小到大)
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
for (int i : a) {
pq.offer(i);
}
while(!pq.isEmpty()) {
System.out.print(pq);
}
}
}
最大堆:PriorityQueue<Integer> pq =new PriorityQueue<>((a, b) -> b - a);