Data Structure Part - priority queue (stack)

Basic properties

Priority queue, also known as binary heap, pile (not to in-memory heap confused, not a thing, is a region of memory, a data structure).

Essentially heap is a complete binary tree, divided into:

  • Min-heap (heap rootlets) : tree, each non-leaf node is not greater than the value of the left and right child nodes, the root node is the smallest stack, FIG. (A).

  • Maximum heap (heap large root) : tree, each non-leaf node is not smaller than the value of the left and right child nodes, the root node is the largest stack, FIG. (B).

Basic Operations

For example are large root heap

Storage

The stack is essentially a complete binary tree, using the storage array, from (a [1] \) \ start storing, and for the subscript \ (K \) nodes \ (a [k] \) is its left child at index \ (2 * k \) , right child under labeled \ (2 * k + 1 \) . And whether \ (k \) is odd or even, his father nodes (if any) is $ \ left \ lfloor k / 2 \ right \ rfloor $.

Upward adjustment

If we insert an element into a heap, it remains to heap structure. How should I do it?

Finally, after the last is a complete binary tree node may want to add to the elements in the array, then adjusted upwards (heapinsert). To adjust the upward adjustment always compared with the father node junction, if the weight value is larger than the father node, and then exchange its father node, the comparison is repeated until the value reaches the top of the stack or the father node until the larger. Adjusted upward diagram below:

Code below, the time complexity is \ (O (logN) \) :

void heapinsert(int* arr, int n) {
    int k = n;
    //如果 K 结点有父节点,且比父节点的权值大
    while (k > 1 && arr[k] > arr[k / 2]) {
        //交换 K 与父节点的值
        swap(arr[k / 2], arr[k]);
        k >>= 1;
    }
}

Adding this element is very simple

void insert(int* arr, int n, int x) {
    arr[++n] = x;//将x置于数组末尾
    heapinsert(arr, n);//向上调整x
}

Downward adjustment

If we want to remove a heap top of the heap element, it remains to heap structure. How should I do it?

After removal of the top of the stack element, the last mobile element to the top of the stack, and this downward adjustment elements (heapify), always to be adjusted downward adjustment nodes \ (K \) to its left child node Comparative if there are children in the weight ratio of the current node \ (K \) large, then the weight of which will be the largest of the child node to node \ (K \) , repeated comparisons, until the node \ (K \) is a leaf node or nodes \ (K \) values are far greater than the child node. Downward adjustment diagram below:

Code below, the time complexity is \ (O (logN) \) :

void heapify(int* arr, int k, int n) {
    //如果结点 K 存在左孩子
    while (k * 2 <= n) {
        int left = k * 2;
        //如果存在右孩子,并且右孩子的权值大于左孩子
        if (left + 1 <= n && arr[left] < arr[left + 1])
            left++; //就选中右孩子
        //如果节点 K 的权值已经大于左右孩子中较大的节点
        if (arr[k] > arr[left])
            break;
        swap(arr[left], arr[k]);
        k = left;
    }
}

Such delete top of the heap element will become very simple

void deleteTop(int* arr, int n) {
    arr[1] = arr[n--];//用最后一个元素覆盖第一个元素,并让n-1
    heapify(arr, 1, n);
}

Built heap

Top-down heap construction

Top-down heap idea is to build from the first \ (i = 1 \) elements begin, be adjusted upwards, always before the \ (i \) elements to keep the stack structure. Time complexity \ (O (nlogn) \)

void ArrayToHeap(int *a,int n) {
    for (int i = 1; i <= n; i++) {
        heapinsert(a, i);
    }
}

Bottom-up heap construction

Bottom-up construction of the heap idea is to start from the end $ i = \ left \ lfloor n / 2 \ right \ rfloor $ elements, be adjusted downward, after always let \ (ni \) elements to keep the stack structure.

void ArrayToBheap(int *a, int n) {
    int i = n / 2;
    for (; i >= 1; i--) {
        heapify(a, i, n);
    }
}

If only visual observation on the code, binary heap structure will come a time complexity is \ (O (nlogn) \) results. Of course, this upper bound is correct, but not asymptotically bounded, it can be observed in the different nodes running heapifyhigh time the node tree (tree height refers to the value of the node to the leaf nodes of the lowest level, Do not be confused depth) relevant, but most of the height of the junction is very small. The use of the following properties can get a more accurate asymptotic boundary:

  • A height \ (H \) comprising \ (n-\) elements stack, there \ (H = \ lfloor logN \ rfloor \) , containing up \ (\ lceil \ frac {n } {2 ^ {k + 1 }} \ rceil \) height \ (K \) node

[Painting stars tree can try, see Introduction to Algorithms concrete proof]

In a height \ (H \) on the node running heapifycost is \ (O (H) \) , we can be built top-down stack overall complexity is expressed as
\ [\ sum ^ {h} _ {k = 0} \ lceil \ frac {n} {2 ^ {k + 1}} \ rceil O (h) = O (n \ sum ^ {h} _ {k = 0} \ frac {k} {2 ^ {k}}) \]
this equation
\ [\ sum ^ {h}
_ {k = 0} \ frac {k} {2 ^ {k}} \] fact, prior to the evaluation \ (n-\) items and , knowledge of high school math
\ [T (k) = \ frac {1} {2} + \ frac {2} {2 ^ 2} + \ frac {3} {2 ^ 3} + \ cdots + \ frac {k} {2 ^ k} \\\ frac { 1} {2} T (k) = \ frac {1} {2 ^ 2} + \ frac {2} {2 ^ 3} + \ frac {3} {2 ^ 4} + \ cdots + \ frac {k-1} {2 ^ k} + \ frac {k} {2 ^ k + 1} \\ T (k) - \ frac {1} {2} T (k) = \ frac {1} {2} + \ frac {1} {2 ^ 2} + \ frac {1} {2 ^ 3} + \ cdots + \ frac {1} {2 ^ k} - \ frac {k} { 2 ^ {k + 1}} \\\ frac {1} {2} T (k) = \ frac {\ frac {1} {2} (1 - (\ frac {1} {2}) ^ k) } {1- \ frac {1} {2}} - \ frac {k} {2 ^ {k + 1}} \\ T (k) = 2- \ frac {1} {2 ^ {k-1} } - \ frac {k} {
2 ^ {k}} \] here can request limit, knowledge of mathematics \ (\ frac {1} { 2 ^ {k-1}} \)When \ (K \) when the limit is to infinite \ (0 \) , for \ (\ frac {k} { 2 ^ {k}} \) a limit is Hospital Rule \ (0 \)

That is, when \ (\ H) tends to infinity, \ (O (n-\ SUM _ ^ {H} = {0} K \ K FRAC {} {} 2 ^ {K}) = O (n-\ CDOT 2) \) , remove the constant term, the bottom-up construction complexity of the stack \ (O (n) \)

Heapsort

Thought HEAPSORT: Suppose there is a big heap root \ (n-\) elements, each of the \ (1 \) element, the first \ (n-\) th switching elements, the first element is adjusted downward (heapify), and such that \ (. 1-n-n-= \) , until \ (n = 1 \)

void heapSort(int* arr, int n) {
    //先自底向上建堆
    int i = n / 2;
    for (; i >= 1; i--) {
        heapify(arr, i, n);
    }

    for (int i = 50; i > 1; i--) {
        swap(arr[1], arr[i]);
        heapify(arr, 1, i - 1);
    }
}

example

Looking for a large element of K

First, a construct with the first k elements of the array rootlets stack , and then traverse the top of the stack and the remaining array comparison, if the current element is greater than the top of the stack, the elements put on top of the stack the current location, and adjusts the stack (heapify). After traversing the end, top of the heap is an array minimum maximum k elements are , that is, k-th largest element .

void heapify(int* a, int index, int length) {
    int left = index * 2 + 1;
    while (left <= length) {
        if (left + 1 <= length - 1 && a[left + 1] > a[left])left++;
        if (a[index] > a[left])break;
        swap(a[index], a[left]);
        index = left;
    }
}

void ArrayToBheap(int* a, int length) {
    int i = length / 2 - 1;
    for (; i >= 0; i--) {
        heapify(a, i, length);
    }
}

void FindKMax(int* a, int k, int length) {
    ArrayToBheap(a, k);
    for (int i = k; i < length; i++) {
        if (a[i] > a[0]) a[0] = a[i];
        heapify(a, 0, k);
    }
}

Time complexity \ (O (n-) \) , is just an example.

In fact, for this problem is a faster approach, thinking quick sort, the time complexity \ (O (logn) \)

int Search_K(int left, int right, int k) {
    int i = left, j = right;
    int p = rand() % (right - left + 1) + left;
    int sign = a[p];
    swap(a[p], a[i]);
    while (i < j) {
        while (i < j && a[j] >= sign)j--;
        while (i < j && a[i] <= sign)i++;
        swap(a[i], a[j]);
    }
    swap(a[i], a[left]);
    if (i - left + 1 == k)return a[i];
    if (i - left + 1 < k)return Search_K(i + 1, right, k - (i - left + 1));
    else return Search_K(left, i - 1, k);
}

Heaps more time, because it was built heap \ (O (the n-) \) , adjust \ (O (logN) \) , when you need to order to get some data is better than the sort ( \ (O (nlogn) \ ) ) algorithm, and if the data is dynamically increase the size of the pile to be completely superior to the sorting algorithm in C ++ STL there is a heap of implementation, called priority_queue.

Guess you like

Origin www.cnblogs.com/czc1999/p/11823460.html