一、 树
1. 树的定义
树(英语:Tree)是一种无向图(undirected graph),其中任意两个顶点间存在唯一一条路径。或者说,只要没有回路的连通图就是树。
二叉树(英语:Binary tree)是每个节点最多只有两个分支(不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”和“右子树”。二叉树的分支具有左右次序,不能颠倒。
完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。
平衡二叉树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
2. 树的应用:
快速数据检索:
- STL的红黑树
- 数据库的B+树
文档结构组织:DOM
人工智能:决策树
游戏:通过构造空间树实现快速碰撞检测( https://www.zhihu.com/question/25111128 )
区块链的默克尔树
3. 常用算法
递归:树的深度优先遍历(https://blog.youkuaiyun.com/weixin_41876155/article/details/80905220)
二叉查找树:左节点值 < 根节点值 < 右节点值
队列:树的广度优先遍历(分层遍历)(https://blog.youkuaiyun.com/weixin_41876155/article/details/80905220)
二、堆
1. 堆的定义
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质:
- 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。---> 最小堆/最大堆
- 堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
- 根节点i,左节点2 * i + 1,右节点2 * i + 2。
2. 建堆的过程:
代码实现: (Lintcode 130: Heapify)
Description
Given an integer array, heapify it into a min-heap array.
For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] is the right child of A[i].
Example
Given [3,2,1,4,5], return [1,2,3,4,5] or any legal heap array.
Challenge
O(n) time complexity.
解答(超时)--- 神奇的是,把函数拉出来就不超时了,待我后面慢慢研究一下……
思路:找到叶子节点和它的根节点比较
public class Solution {
/*
* @param A: Given an integer array
* @return: nothing
*/
public void heapify(int[] A) {
// write your code here
for(int i = (A.length - 1)/2; i >= 0; --i){
while(i < A.length){
int left = 2 * i + 1;
int right = 2 * i + 2;
int min_pos = i;
if(left < A.length && A[left] < A[min_pos]){
min_pos = left;
}
if(right < A.length && A[right] < A[min_pos]){
min_pos = right;
}
if(min_pos != i){
int temp = A[i];
A[i] = A[min_pos];
A[min_pos] = temp;
i = min_pos;
}
else{
break;
}
}
}
}
}
建堆的复杂度分析:
- N个节点的堆高度最大为h = logN,最下面一层非叶子节点最多调整1次,倒数第2层最多2次,…依此类推,根节点最多需要h次。
- 最下面一层子节点共有2^(h-1)个,倒数第2层有2^(h-2)个,…依此类推,根节点有2^(h-h)个1个。
- 所以总的时间复杂度为1^(h-1) + 2*2^(h-2) + (h-1)*2 + h,得到结果为N*2 – 2 – log(N),所以时间复杂度O(n)。
3. Merge K Sorted List
Description
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
Solution:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists==null || lists.length == 0)
return null;
PriorityQueue<ListNode> queue = new PriorityQueue<ListNode>(new Comparator<ListNode>(){ //用优先队列实现堆
public int compare(ListNode l1, ListNode l2){
return l1.val - l2.val;
}
});
ListNode head = new ListNode(0);
ListNode p = head;
for(ListNode list: lists){
if(list != null)
queue.offer(list); //维护一个最小堆,入堆list个元素,如示例,1,1,2
}
while(!queue.isEmpty()){
ListNode n = queue.poll();
p.next = n;
p = p.next;
if(n.next != null) //入堆4
queue.offer(n.next);
}
return head.next;
}
}
3. 堆的应用
优先任务调度
- 操作系统如何根据线程优先级进行快速调度?
海量数据多路归并排序
- 面试最爱问题,海量数据排序选择topK。