zoukankan      html  css  js  c++  java
  • 二叉堆 堆排序 優先隊列

    二叉堆是一个近似完满二叉树的结构,并同时满足堆的性质:
    即子结点的键值或索引总是小于(或者大于)它的父节点。

    通常堆是通过一维数组来实现的。在起始数组为 0 的情形中:
    父节点i的左子节点在位置 (2*i+1);
    父节点i的右子节点在位置 (2*i+2);
    子节点i的父节点在位置 floor((i-1)/2);

    在堆的数据结构中,堆中的最大值总是位于根节点。

    堆中定义以下几种操作:
    堆调整(heapify):将堆的末端子结点作调整,维持堆的性质
    创建堆(build_heap):将一个无序数组构造为一个堆。
    堆排序(heap_sort):移除位在第一个数据的根结点,并做堆调整的递归运算

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    int parent(int);
    int left(int);
    int right(int);
    void heapify(int [], int, int);
    void build_heap(int [], int);
    void heap_sort(int [], int);
    
    static void swap(int* a, int* b)
    {
        int temp = *b;
        *b = *a;
        *a = temp;
    }
     
    int parent(int i)
    {
        return (int)floor((i - 1) / 2);
    }
     
    int left(int i)
    {
        return (2 * i + 1);
    }
     
    int right(int i)
    {
        return (2 * i + 2);
    }
     
    /*
     * 堆调整。
     * 以 left(i) 和 right(i) 为根的俩棵子树都已经是堆,
     * 这时A[i]可能小于其子女,所以要进行调整。
     *
     * 调整结果是,以A[i]为根的子树成为一个堆。
     * */
    void heapify(int A[], int heap_size, int i)
    {
        int l = left(i);
        int r = right(i);
        int largest;
        int temp;
        if (l < heap_size && A[l] > A[i])  {
            largest = l;
        }
        else {
            largest = i;
        }
    
        if (r < heap_size && A[r] > A[largest])  {
            largest = r;
        }
    
        if (largest != i) {
            swap(A+i, A+largest);
            heapify(A, heap_size, largest);
        }
    }
    /* 
     * 将数组A调整为一个堆。
     * 数组A[parent(n-1)]之后的元素都是堆树中的叶子节点。
     * */
    void build_heap(int A[], int heap_size)
    {
        int i = parent(heap_size-1);
        for (; i >= 0; i--) 
            heapify(A, heap_size, i);
    }
    /*
     * 每次将堆中最大的元素
     * */
    void heap_sort(int A[], int n)
    {
        /* 使A[0]称为最大的元素 */
        build_heap(A, n);
    
        /* 将堆中最后一个叶子节点去掉,还是一个堆,只是堆的大小发生改变。
         * 去掉A[i]后的堆称为新堆,新堆的大小为i。
         * 将新堆的根节点A[0]改为A[i],这时堆的性质发生改变,需要重新调整。
         * 新堆是A[0...i-1], A[i]用来保存原堆的根节点。
         * */
        for(int i = n-1; i >= 0; i--) {
    
            swap(A, A+i);
    
            heapify(A, i, 0);
        }
    }
    
    void print_heap(int A[], int n)
    {
        for (int i = 0; i < n; i++) {
            printf("%d ", A[i]);
        }
        printf("\n");
    }
    
    #define NUMOF(a) sizeof(a)/sizeof(a[0])
    /*輸入資料並做堆積排序*/
    int main(int argc, char* argv[])
    {
        int A[] = {19, 1, 10, 14, 16, 4, 7, 9, 3, 2, 8, 5, 11};
        heap_sort(A, NUMOF(A));
        print_heap(A, NUMOF(A));
        return 0;
    }

    高效尤先级队列

    主要應用堆的下面兩個操作實現。

     #define MAX_HEAP_NUM 100

    #define ERR_HEAP_DATA -1
    typedef int HeapDat;
    typedef struct heap_tag {
        int size;
        HeapDat data[MAX_HEAP_NUM];
    } Heap;
    
    int heap_insert(Heap *heap, HeapDat new_data)
    {
        if(heap->size < MAX_HEAP_NUM) {
            HeapDat * heapdata = heap->data;
            int i = heap->size++;
    
            for (; i>=0 && heapdata[parent(i)] < new_data; i=parent(i))
                heapdata[i] = heapdata[parent(i)];
            heapdata[i] = new_data;
    
            return 0;
        }
        else 
            return -1;
    }
    
    
    HeapDat heap_extract_max(Heap *heap)
    {
        HeapDat max = heap->data[0];
        if (heap->size < 1)
            return ERR_HEAP_DATA;
        heap->size--;
        heap->data[0] = heap->data[heap->size];
    
        heapify(heap->data, heap->size, 0);
        return max;  
    }
    
    int main(int argc, char* argv[]) { Heap h = { 13, {19, 1, 10, 14, 16, 4, 7, 9, 3, 2, 8, 5, 11}, }; build_heap(h.data, h.size); print_heap(h.data, h.size); heap_insert(&h, 18); print_heap(h.data, h.size); heap_extract_max(&h); print_heap(h.data, h.size); return 0; }

     另一種建堆的方法:

    int _heap_insert(int A[], int n, int new_data, int *heap_size)
    {
        if(*heap_size < n) {
            int i = *heap_size;
            for (; i>=0 && A[parent(i)] < new_data; i=parent(i))
                A[i] = A[parent(i)];
            A[i] = new_data;
            *heap_size += 1;
            return 0;
        }
        else 
            return -1;
    }
    
    
    /*
     * 利用heap_insert建堆,跟用上面的方法建的堆不一样。
     * */
    void build_heap_2(int A[], int n)
    {
        int heap_size=1; 
        do 
            _heap_insert(A, n, A[heap_size], &heap_size);
        while (heap_size < n);
    }
    
    
    
    /*将A[i] 变为 max(A[i], key); 并重新调整堆
     * */
    void heap_increase_key(int A[], int i, int key)
    {
        if (key > A[i]) {
            A[i] = key;
            for (; i>=0 && A[parent(i) < key]; i=parent(i)) 
                A[i] = A[parent(i)];
            A[i] = key;
        }
    }
    /*
     * 将节点A[i]从堆中删除,并重新调整为新的堆。
     * */
    int heap_delete(int A[], int heap_size,  int i)
    {
        if (i<heap_size) {
            A[i] = A[heap_size-1];
            heapify(A, heap_size, i);
            return 1;
        }
        else
            return 0;
    }
  • 相关阅读:
    tomcat最大线程数的设置(转)
    webService接口大全
    实用工具网站汇总
    Linux常用指令(待补充)
    svn的使用总结(待补充)
    养生
    nodejs知识结构
    NVM node版本管理工具的安装和使用
    MongoDB安装和MongoChef可视化管理工具的使用
    JavaScript模块化编程(三)
  • 原文地址:https://www.cnblogs.com/prajna/p/2935946.html
Copyright © 2011-2022 走看看