1. 程式人生 > >《Data Structure And Algorithm Analysis In C++》讀書筆記六

《Data Structure And Algorithm Analysis In C++》讀書筆記六

Chapter 6 Priority Queues(Heaps)

* Efficient implementation of the priority queue ADT.

* Use of priority queues.

* Advanced implementations of priority queues.

6.1 Model

priority queue ADT interface:

insert(equivalent of enqueue)

deleteMin(dequeue)


Priority queue have many applications besides operating systems. and external sorting, greedy algorithms.

6.2 Simple Implementations

Linklist, insertion O(1), deleteMin O(N).

sorted list, insertion O(N), deleteMin O(1).

BinarySearchTree insertion O(logN), deleteMin O(logN). Because we delete the min element from the BST which will effect the balance of the tree. In worst case it could produce a linklist

Binary Heap support both operation in O(logN) worst-case time. Insertion will take constant time on average.

6.3 Binary Heap

Binary Heap is a data structure could implementation the priority queue ADT.

6.3.1 Structure Property

Heap is a binary tree that is completely filled, except the bottom level, which is filled from left ro right.

Such a tree is known as complete binary tree.


For any element in array position i, the left child is in position 2i, the right child is in the cell after the left child(2i + 1).

the parent is in floor(i/2).

The class interface for priority queue

#ifndef BINARY_HEAP_H
#define BINARY_HEAP_H


#include <algorithm>
#include <vector>

template <typename Comparable>
class BinaryHeap{
  public:
    explicit BinaryHeap(int capacity = 100);
    explicit BinaryHeap(const std::vector<Comparable> &items);

    bool isEmpty() const;
    const Comparable &findMin() const;

    void insert(const Comparable &x);
    void insert(Comparable &&x);
    void deleteMin();
    void deleteMin(Comparable &minItem);
    void makeEmpty();
 
  private:
    int currentSize;                    // Number of elements in heap
    std::vector<Comparable> array;      // The heap array

    void buildHeap();
    void percolateDown(int hole);
};

#endif

6.3.2 Heap-Order Property

6.3.3 Basic Heap Operations

insert

deleteMin

6.3.4 Other Heap Operations

deceaseKey  O(logN)

increaseKey O(logN)

remove  decreaseKey(p, infinite), then performing deleteMin().  O(logN)

buildHeap O(N)

6.4 Application of Priority Queues

6.4.1 The Selection Problem

1A. sorted all elemts and choose the k-th,  O(NlogN)

2B, maintain a array with k, sorted then O(klogK), then compare the raming item with the smallest one, 

    if it is less, then ignore the coming item.

    if it is larger, then remove the smallest one and do an one item insertion sort O(k).

    the total time complexity is O(klogK + (n-k)*k)

6A, read the N element into an array. and apply the buildHeap O(N).

    then we do the deleteMin n times,the last element extracted from the heap is our result. O(klogN)

    total time complexity is O(N + klogN)

    if k = N ,it is the model for heapsort.

6B, selection k elements and build heap O(k), then compare the raming item with the findmin

    if the coming item is larger, then do the deletemin and insert O(logk)

    if the coming item is less, do nothing

   total time complexity is O(k + (N-k)logk)   O(Nlogk)

6.4.2 Event Simulation

6.5 d-Heaps


4-heaps may outperform binary heaps in practice.

6.6 Leftist Heaps(左傾堆)

leftist heap has a structural property and an ordering property, a leftist heap is also a binary tree. But is is not perfect balanced.

6.6.1 Leftist Heap Property

null path length, npl(X), of any node X to be the length of the shortest path from X to a node without two children.


null path length of any node is 1 more than the minimum of the null path lengths of its children.

The leftist heap property: for every node X in the heap, the null path length of the left child is at least as large as that of the right child.

A leftist tree with r nodes on the right path must have at least 2^r -1 nodes.



by the theorem, the leftist ree of N nodes has a right path containing at most floor(log(N+1)) nodes.

6.6.2 Leftist Heap Operations

the normal operation is merge.

Insertion is special case of merge.

1) comopare the roots. recursively merge the heap with the large root with the right subheap of the heap with the smaller root.

ref implementation:

https://github.com/sesiria/Algs/blob/master/Lib/LeftistHeap.h

6.7 Skew Heaps(斜堆)

A skew heap is a self-adjusting version of a leftist heap.

A skey heap vs leftis heap like(splay tree vs the AVL tree).

one merge operation worst case is O(N).

for any M consecutive opeartions, the total worst-case running time is O(MlogN), O(logN) amortized cost per operation.

6.8 Binomial Queues(二項佇列)

leftist and skew heaps support merge, insertion, and deletMein in O(logN)

Binomial queues support all three operation in O(logN) worst-case time per operations, but insertions take constant time on average

6.8.1 Binomial Queue Structure

A collection of heap-ordered trees, known as a forest.

Each of the heap-ordered trees is of a constrained form known as a binomial tree

6.8.2 Binomial Queue Operations

findMin of binomial queue is O(logN).

if we maintain knowledge of the minimum and update the minimum when it changes during other opeartions.

we can perform the findMin operation in O(1) time

the merge operation take O(logN) in worst

6.8.3 Implementation of Binomial Queues

std::priority_queue<T> pq;
std::priority_queue<T, std::vector<T>, cmp> pq;

#include <queue>

the STL implements a max-heap rather than a min-heap

member functions

void push(const Object &x);

const Object & top() const;

void pop();

bool empty();

void clear();

example code to use the priority_queue as max-heap or min-heap

#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <string>
using namespace std;

// Empty the priority queue and print its contents.
template <typename PriorityQueue>
void dumpContents(const string &msg, PriorityQueue &pq)
{
    cout << msg << ":" << endl;
    while(!pq.empty())
    {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;
}

// Do some inserts and removes (done in dumpContents).

int main(int argc, char **argv)
{
    priority_queue<int> maxPQ;
    priority_queue <int, vector<int>, greater<int>> minPQ;

    for (int i = 0; i < 10; ++i)
    {
        minPQ.push(i);
        maxPQ.push(i);
    }

    dumpContents("minPQ", minPQ);
    dumpContents("maxPQ", maxPQ);

    return 0;
}

The running result is :