1.堆的基礎java
2.徹底二叉樹算法
徹底二叉樹是效率很高的數據結構,徹底二叉樹是由滿二叉樹而引出來的。對於深度爲K的,有n個結點的二叉樹,當且僅當其每個結點都與深度爲K的滿二叉樹中編號從1至n的結點一一對應時稱之爲徹底二叉樹。
(通俗來講:徹底二叉樹不必定是滿二叉樹,當一層已滿容納不下新的節點時,新的一層從左至右來盛放新節點,缺失的節點必定在右側)
最大堆:堆中某個節點的值老是不大於其父節點的值(相應的,能夠定義最小堆)
segmentfault
3.用數組存儲二叉堆
api
4.基礎代碼實現數組
這裏的
ArrayNew
是我以前實現的數組:
數組代碼
public class Heap<E extends Comparable<E>> { private ArrayNew<E> data; public Heap(int capacity) { data = new ArrayNew<>(capacity); } public Heap() { data = new ArrayNew<>(); } // 返回堆中的元素個數 public int size() { return data.getSize(); } // 堆中是否包含元素 public boolean isEmpty() { return data.isEmpty(); } // 父節點的索引 private int parent(int index) { if (index == 0) { throw new IllegalArgumentException("index-0 doesn't have parent"); } return (index - 1) / 2; } // 左子節點的索引 private int leftChild(int index) { return 2 * index + 1; } // 右子節點的索引 private int rightChild(int index) { return 2 * index + 2; } }
5.添加元素(sift up
)
數據結構
步驟:ide
// 添加元素 public void add(E e) { data.addLast(e); siftUp(data.getSize() - 1); } // 上浮 private void siftUp(int index) { // 添加的元素大於父節點的元素 while (index > 0 && data.get(index).compareTo(data.get(parent(index))) > 0) { data.swap(index, parent(index)); index = parent(index); } }
6.取出元素(sift down
)性能
步驟:優化
// 查看堆中的最大值 public E findMax() { if (data.isEmpty()) { throw new IllegalArgumentException("can't find Max in empty heap"); } return data.get(0); } // 取出堆中的最大值 public E extractMax() { E ret = data.get(0); data.swap(0, data.getSize() - 1); data.removeLast(); siftDown(0); return ret; } // 下沉 private void siftDown(int index) { while (leftChild(index) < data.getSize()) { // 有子節點(左子節點沒有越界) int j = leftChild(index); // 有右子節點,而且右節點元素大於左節點元素 if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0) { j = j + 1; } // 此時,data[j]就是左右子節點的最大節點值 if (data.get(j).compareTo(data.get(index)) <= 0) { break; } data.swap(index, j); index = j; } }
7.Heapify和replacethis
replace(取出堆中的最大元素,再放入一個新的元素)
extractMax
再add
,可是這樣會有兩次O(logn)
操做siftDown
,這樣只有一次O(logn)
操做// 取出堆中的最大元素,並替換成元素e,從新siftDown public E replace(E e) { E ret = data.get(0); data.set(0, e); siftDown(0); return ret; }
heapify(將任意數組整理成堆的形狀)
優化:heapify(算法複雜度是O(n))
siftDown
就能夠了// heapify public Heap(E[] arr) { data = new ArrayNew<>(arr); for (int i = parent(data.getSize() - 1); i > 0; i--) { siftDown(i); } }
8. 複雜度分析
由於堆的取出和添加複雜度都是O(logn),因此堆的性能是很高的。
操做 | 時間複雜度 |
---|---|
add | O(logn) |
extractMax | O(logn) |
1.優先隊列基礎
2.隊列接口
public interface Queue<E> { int getSize(); boolean isEmpty(); void enqueue(E e); E dequeue(); // 查看隊首元素 E getFront(); }
3.基於堆的優先隊列代碼實現
public class priorityQueue<E extends Comparable<E>> implements Queue<E> { Heap<E> data; public priorityQueue() { data = new Heap<>(); } @Override public int getSize() { return data.size(); } @Override public boolean isEmpty() { return data.isEmpty(); } @Override public void enqueue(E e) { data.add(e); } @Override public E dequeue() { return data.extractMax(); } @Override public E getFront() { return data.findMax(); } }
4.LeetCode中有關優先隊列的問題
347. 前K個高頻元素
題目:347. 前K個高頻元素
描述:給定一個非空的整數數組,返回其中出現頻率前 k 高的元素。
例子:
示例 1: 輸入: nums = [1,1,1,2,2,3], k = 2 輸出: [1,2] 示例 2: 輸入: nums = [1], k = 1 輸出: [1]
解決代碼:
import java.util.ArrayList; import java.util.List; import java.util.TreeMap; // 只須要在`Solution`這個類中引入所須要的類便可 // 全部的類均可以在以前的博客中找到 public class Solution { private class Freq implements Comparable<Freq> { public int e, freq; public Freq(int e, int freq) { this.e = e; this.freq = freq; } @Override public int compareTo(Freq another) { if (this.freq < another.freq) { return 1; } else if (this.freq > another.freq) { return -1; } else { return 0; } } } public List<Integer> topKFrequent(int[] nums, int k) { TreeMap<Integer, Integer> map = new TreeMap<>(); for (int num : nums) { if (map.containsKey(num)) { map.put(num, map.get(num) + 1); } else { map.put(num, 1); } } PriorityQueue<Freq> pq = new PriorityQueue<>(); for (int key : map.keySet()) { if (pq.getSize() < k) { pq.enqueue(new Freq(key, map.get(key))); } else if (map.get(key) > pq.getFront().freq) { pq.dequeue(); pq.enqueue(new Freq(key, map.get(key))); } } ArrayList<Integer> list = new ArrayList<>(); while (!pq.isEmpty()) { list.add(pq.dequeue().e); } return list; } }