优先队列--堆

当你只需要找到最大最小值而不需要查找其他元素时,可以用二叉堆,不需要用用叉查找树。

Java版

java中的PriorityQueue就是个小顶堆(重写元素的compareTo方法可以轻易地改为大顶堆),但是它不能设置堆的最大容量,所以我自己实现了一个MinHeap。

import java.util.ArrayList;
import java.util.List;

/**
 * 小根堆。可用于取topK、排序等。<br>
 * MinHeap相对于PriorityQueue的优势在于:PriorityQueue是不能设置容量上限的;MinHeap可设置容量上限带来两个好处,
 * 一是内存占用可控
 * ,二是提高添加和删除元素的速度(PriorityQueue和MinHeap增删元素时间复杂度都是logN,但是MinHeap中的N是有上限的
 * ,所以达到上限后MinHeap更快一些)
 * 
 * @Author:orisun
 * @Since:2016-5-25
 * @Version:1.0
 */
@SuppressWarnings("rawtypes")
public class MinHeap<T extends Comparable> {

    private List<T> data;
    private int maxSize;

    /**
     * 
     * @param maxSize
     *            指定堆的最大容量
     */
    public MinHeap(int maxSize) {
        data = new ArrayList<T>(maxSize);
        if (maxSize > 0) {
            this.maxSize = maxSize;
        }
    }

    public int size() {
        return data.size();
    }

    public boolean isEmpty() {
        return data.size() == 0;
    }

    /**
     * 取出堆中存储的元素(不保证顺序)<br>
     * 时间复杂度O(1)
     * 
     * @return
     */
    public List<T> getTopK() {
        return data;
    }

    public void clear() {
        data.clear();
    }

    private void swap(int i, int j) {
        T tmp = data.get(j);
        data.set(j, data.get(i));
        data.set(i, tmp);
    }

    @SuppressWarnings("unchecked")
    private void heapDown(int i) {
        int l = (i + 1) * 2 - 1;// 左孩子的index
        int r = (i + 1) * 2;// 右孩子的index
        int smallest = i;// 父节点、左、右孩子中的最小者
        // 如果左孩子存在,且左孩子小于smallest
        if (l < data.size() && data.get(l).compareTo(data.get(smallest)) < 0) {
            smallest = l;
        }
        // 如果右孩子存在,且左孩子小于smallest
        if (r < data.size() && data.get(r).compareTo(data.get(smallest)) < 0) {
            smallest = r;
        }
        // 如果父节点本来就比左右孩子小,则直接返回
        if (i == smallest) {
            return;
        }
        // 父节点跟较小的那个子节点交换
        swap(i, smallest);
        // 交换后影响到了子树,所以对子树递归进行heapify
        heapDown(smallest);
    }

    @SuppressWarnings({ "unchecked" })
    private void heapUp(int i) {
        while (i > 0) {
            T ele = data.get(i);
            int p = (i - 1) / 2;// 父节点的index
            if (ele.compareTo(data.get(p)) < 0) {// 如果比父节点小,则跟父节点交换
                swap(i, p);
                i = p;
            } else { // 否则停止
                break;
            }
        }
    }

    /**
     * 获取堆顶元素(即堆中最小的元素)<br>
     * 时间复杂度O(1)
     * 
     * @return
     */
    public T getRoot() {
        return data.get(0);
    }

    /**
     * 向堆中添加一个元素<br>
     * 时间复杂度O(logN)
     * 
     * @param ele
     */
    @SuppressWarnings("unchecked")
    public void add(T ele) {
        int size = data.size();
        if (size == 0) {// 如果容器为空,则直接插入即可
            data.add(ele);
            return;
        }
        if (size < maxSize) {// 未达容量上限
            data.add(ele);// 直接插到末位置上
            heapUp(size);// 然后从末位置开始向上调整
        } else {// 如果已达容量上限
            if (ele.compareTo(data.get(0)) > 0) {// 如果不能比根节点大,则直接丢弃
                data.set(0, ele); // 替换根节点
                heapDown(0); // 然后从根节点开始向下调整
            }
        }
    }

    /**
     * 删除堆顶元素<br>
     * 时间复杂度O(logN)
     */
    public void delRoot() {
        int size = data.size();
        if (size > 0) {
            T lastEle = data.get(size - 1);
            if (size > 1) {
                // 用末元素替换根节点
                data.set(0, lastEle);
                data.remove(size - 1);
                // 然后从根节点开始向下调整
                heapDown(0);
            } else {
                data.remove(size - 1);
            }
        }
    }

    /**
     * 删除并返回堆顶元素。通过不断地poll,可以有序地取出堆中的所有元素<br>
     * 时间复杂度O(logN)
     * 
     * @return
     */
    public T poll() {
        T rect = null;
        int size = data.size();
        if (size > 0) {
            rect = getRoot();
            delRoot();
        }
        return rect;
    }
}

 

C++版

1 #include<vector>
2 #include<iostream>
3  using std::cin;
4  using std::cout;
5  using std::vector;
6  using std::endl;
7
8 template <typename Comparable>
9  class BinaryHeap{
10 public:
11 explicit BinaryHeap(int capacity=100);
12 explicit BinaryHeap(const vector<Comparable>& items)
13 :array(items.size()+10),currentSize(items.size()){
14 for(int i=0;i<items.size();i++)
15 array[i+1]=items[i];
16 buildHeap();
17 }
18
19 bool isEmpty() const;
20 const Comparable & findMin() const;
21
22 void insert(const Comparable & x);
23 void deleteMin();
24 void deleteMin(Comparable & minItem);
25 void makeEmpty();
26
27
28 int currentSize;
29 vector<Comparable> array;
30 private:
31 void buildHeap();
32 void percolateDown(int hole);
33 };
34
35 template <typename Comparable>
36  bool BinaryHeap<Comparable>::isEmpty() const{
37 return currentSize==0;
38 }
39
40 template <typename Comparable>
41  void BinaryHeap<Comparable>::insert(const Comparable & x){
42 if(currentSize==array.size()-1)
43 array.resize(array.size()*2);
44 int hole=++currentSize;
45 for(;hole>1&&x<array[hole/2];hole/=2)
46 array[hole]=array[hole/2];
47 array[hole]=x;
48 }
49
50 template <typename Comparable>
51  void BinaryHeap<Comparable>::deleteMin(){
52 if(isEmpty())
53 throw;// UnderflowException();
54   array[1]=array[currentSize--];
55 percolateDown(1);
56 }
57
58 template <typename Comparable>
59  void BinaryHeap<Comparable>::deleteMin(Comparable & minItem){
60 if(isEmpty())
61 throw;// UnderflowException();
62   minItem=array[1];
63 array[1]=array[currentSize--];
64 percolateDown(1);
65 }
66
67 template <typename Comparable>
68  void BinaryHeap<Comparable>::percolateDown(int hole){
69 int child;
70 Comparable tmp=array[hole];
71 for(;hole*2<=currentSize;hole=child){
72 child=hole*2;
73 if(child!=currentSize&&array[child+1]<array[child])
74 child++;
75 if(array[child]<tmp)
76 array[hole]=array[child];
77 else
78 break;
79 }
80 array[hole]=tmp;
81 }
82
83 template <typename Comparable>
84  void BinaryHeap<Comparable>::buildHeap(){
85 for(int i=currentSize/2;i>0;i--)
86 percolateDown(i);
87 }
88
89  int main(){
90 vector<int> array;
91 for(int num=150;num>10;num-=10)
92 array.push_back(num);
93 BinaryHeap<int> heap(array);
94 for(int i=1;i<=heap.currentSize;i++)
95 cout<<heap.array[i]<<"";
96 cout<<endl;
97
98 int min=0;
99 heap.deleteMin(min);
100 cout<<"The minimun value of heap:"<<min<<endl;
101
102 for(int i=1;i<=heap.currentSize;i++)
103 cout<<heap.array[i]<<"";
104 cout<<endl;
105
106 return0;
107 }
108  

D:\C++>g++ BinaryHeap.cpp -o BinaryHeap
D:\C++>BinaryHeap.exe

20  50  30  70  60  40  90  80  120  140  110  150  100  130

The minimun value of heap:20

30  50  40  70  60  100  90  80  120  140  110  150  130

STL中的priority_queue

函数配接器Function Adapter

能够将仿函数和另一个仿函数结合起来的仿函数。函数配接器声明于<functional>中。

Priority Queue定义于文件<queue>中,其声明如下:

    template<typename _Tp,
             typename _Sequence = vector<_Tp>,
             typename _Compare  = less<typename _Sequence::value_type> >
    class priority_queue

1 #include<iostream>
2 #include<vector>
3 #include<queue>
4 #include<functional>
5 #include<string>
6
7  usingnamespace std;
8
9 template <typename PriorityQueue>
10  void dumpContents(conststring& msg,PriorityQueue & pq){
11 cout<<msg<<":"<<endl;
12 while(!pq.empty()){
13 cout<<pq.top()<<endl;
14 pq.pop();
15 }
16 }
17
18  int main(){
19 priority_queue<int> maxPQ;
20 priority_queue<int,vector<int>,greater<int>> minPQ;     //默认情况下用的是less<int>
21
22 minPQ.push(150);minPQ.push(140);minPQ.push(130);minPQ.push(120);minPQ.push(110);minPQ.push(100);minPQ.push(90);
23 maxPQ.push(150);maxPQ.push(140);maxPQ.push(130);maxPQ.push(120);maxPQ.push(110);maxPQ.push(100);maxPQ.push(90);
24
25 dumpContents("minPQ",minPQ);
26 dumpContents("maxPQ",maxPQ);
27
28 return0;
29 }

D:\C++>priority_queue.exe

minPQ:

90

100

110

120

130

140

150

maxPQ:

150

140

130

120

110

100

90

自定义比较方法:

有两种策略可供选择:

(1)自定义比较器

class CMP{
public:
    bool operator() (const Comparable & a,const Comparable &b)const{
        return a.value<b.value;
    }
};

只需要重载operator()就可以了。

(2)在自已的类中重载operator<,因为在priority_queue中使用的默认比较器就是less<object>

class Comparable{
public:
    int value;
    bool operator< (const Comparable &b) const{
        return value<b.value;
    }
};
posted @ 2010-08-26 21:42  张朝阳  阅读(751)  评论(0编辑  收藏  举报