堆排序详解

来源:互联网 发布:java导出txt文件 编辑:程序博客网 时间:2024/06/05 08:37

堆排序是利用堆的堆序性,对于最小堆而言,最小元素在堆顶,对于一个数组先通过将其建立成一个最小堆 然后一个一个删除其堆顶元素既实现了排序。

当堆的顶部最小元素被删除后要对堆做调整使其再次满足堆序性。由于对堆做一次调整最坏时间复杂度为O(logN),堆排序需要对堆做N-1次调整 所以堆排序最坏时间复杂度为O(NlogN),不过其比快排多开辟了一个堆的存储空间。

我们简要分析下堆排序的时间复杂度。我们在每次删除最小元素时都需要对堆做重新调整,这样,每次重新调整堆的时间复杂度变为O(logn),而堆排序时有n-1次重新调整堆的操作,建堆时有((len-1)/2+1)次重新调整堆的操作,因此堆排序的平均时间复杂度为O(n*logn), 最坏时间复杂度也为O(n*logn)

堆排序在排序元素较少时有点大才小用,待排序列元素较多时,堆排序还是很有效的。另外,堆排序在最坏情况下,时间复杂度也为O(n*logn)。相对于快速排序(平均时间复杂度为O(n*logn),最坏情况下为O(n*n)),这是堆排序的最大优点。

堆排序的详细实现如下:

////  sort.c//  test_sort////#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <math.h>typedef int ElementType;#define kMinSentinelElement (-1024)typedef struct _priorityQueue{    int capacity;    int size;    ElementType *elements;}HeapStruct, *PriorityQueue;PriorityQueue initialize(int maxElementsCount);bool insert(PriorityQueue h, ElementType d);bool deleteMin(PriorityQueue h);void traverse(PriorityQueue h);ElementType findMin(PriorityQueue h);ElementType findTail( PriorityQueue h);void heapSort(int arr[], int length);PriorityQueue initialize(int maxElementsCount){    PriorityQueue priorityq = calloc(1, sizeof(HeapStruct));    //add one extra for sentinel sentinel    ElementType *elements = calloc((maxElementsCount + 1), sizeof(ElementType));    priorityq->elements = elements;    priorityq->capacity = maxElementsCount;    priorityq->size = 0;    priorityq->elements[0] = kMinSentinelElement;    return priorityq;}bool insert(PriorityQueue h, ElementType d){        if (h->size + 1 > h->capacity) {        printf("capacity is big\n");        return false;    }        int size = h->size;    if (size == 0) {        h->elements[1] = d;        h->size++;        return true;    }        if (size > 0){                //得到当前要插入的数据的位置        //和其父节点进行比较 判断是否需要交换        //一直判断到父节点的数据满足条件                //当前要插入的数据在数组中的位置        int insertPosition = size + 1;        int fatherNodePosition = floor(insertPosition/2);                if (h->elements[fatherNodePosition] < d) {            h->elements[insertPosition] = d;            h->size++;        }else{            while (h->elements[fatherNodePosition] > d) {                                //将父节点的数据赋给当前插入的节点                h->elements[insertPosition] = h->elements[fatherNodePosition];                insertPosition = fatherNodePosition;                fatherNodePosition = floor(fatherNodePosition/2);                            }                        //将当前要插入的数据放入其父节点            h->elements[insertPosition] = d;            h->size++;        }    }        return true;    }bool deleteMinFunction1(PriorityQueue h){    //put the last element to top    //compare top to (left and right    //when top is small (left and right) stop    //when top is big (left or right) put (left or right samll) to top    //put tail to (left or right samll) go on        //此方法在判断左右子节点时方法较为繁琐    ElementType tail = h->elements[h->size];        h->size--;    for (int i = 1; i <= h->size; ) {        int leftp = i*2;        int rightp = i*2 + 1;                if (leftp > h->size) {            //the last position            h->elements[i] = tail;            return true;        }        if (rightp > h->size && leftp <= h->size) {            //just one left immediate change            if (tail > h->elements[leftp]) {                h->elements[i] = h->elements[leftp];                h->elements[leftp] = tail;            }else{                h->elements[i] = tail;            }            return true;        }        if (tail < h->elements[leftp] && tail < h->elements[rightp]) {            h->elements[i] = tail;            return true;        }else {            int position = h->elements[leftp] < h->elements[rightp] ? leftp : rightp;            h->elements[i] = h->elements[position];            i = position;        }    }        return false;}//对二叉堆按照(结构性和堆序性要求)进行调整void rebulid(PriorityQueue h, int topPosition){    //put the last element to top    //compare top to (left and right    //when top is small left and right stop    //when top is big (left or right) put (left or right samll) to top    //put tail to (left or right samll) go on        ElementType top = h->elements[topPosition];    int lp = topPosition * 2;    int rp = topPosition * 2 + 1;        if (lp > h->size) {        return;    }        if (rp > h->size || lp == h->size) {        //only left        ElementType l = h->elements[lp];        if (l < top) {            //change            h->elements[lp] = top;            h->elements[topPosition] = l;        }        return;    }        ElementType l = h->elements[lp];    ElementType r = h->elements[rp];        if (top < l && top < r) {        return;    }        int rlpsmall = l < r ? lp : rp;    h->elements[topPosition] = h->elements[rlpsmall];    h->elements[rlpsmall] = top;    rebulid(h, rlpsmall);}bool deleteMinByFunction2(PriorityQueue h){    //此方法采用递归一直向下过滤    ElementType tail = h->elements[h->size];    h->elements[1] = tail;    h->size--;    rebulid(h, 1);    return true;}/* 此方法实现较为简洁 */bool deleteMin(PriorityQueue h){    /*     当删除一个最小元时,在根节点处产生了一个空穴,由于现在堆少了一个元素,因此堆     中最后一个元素X必须移动到该堆的某个位置,如果X可以被放到空穴中,那么deleteMin操作完成,不过这一般是不太可能的。因此我们将空穴的两个儿子中较小者     移到空穴,这样就把空穴向下推了一层,重复该步骤直到X可以被放入空穴中。     */        ElementType tail = h->elements[h->size];    h->size--;        for (int i = 1; i <= h->size; ) {        //find left and right min position        int minPosition = 0;        if ((2 * i + 1) <= h->size) {            minPosition = h->elements[2 * i] < h->elements[2 * i + 1] ? (2 * i) : (2 * i + 1);        }else if (2 * i <= h->size){            minPosition = 2 * i;        }else{            //the last position no (left and right)            h->elements[i] = tail;            return true;//compare end        }        if (tail < h->elements[minPosition]) {            h->elements[i] = tail;            return true;//compare end        }else{            h->elements[i] = h->elements[minPosition];            i = minPosition;        }    }        return false;}//下滤void percolateDown( PriorityQueue h, int position){    if (position > h->size) {        return;    }        ElementType top = h->elements[position];        int i = position;        //find left and right min position    int minPosition = 0;    if ((2 * i + 1) <= h->size) {        minPosition = h->elements[2 * i] < h->elements[2 * i + 1] ? (2 * i) : (2 * i + 1);    }else if (2 * i <= h->size){        minPosition = 2 * i;    }else{        //the last position no (left and right)        return;    }        if (top > h->elements[minPosition]) {                h->elements[i] = h->elements[minPosition];        h->elements[minPosition] = top;                percolateDown(h, minPosition);    }}ElementType findTail( PriorityQueue h){    int size = h->size;    if (size <= h->capacity) {        printf("the findTail is %d\n", h->elements[size]);        return h->elements[size];    }    return kMinSentinelElement;}ElementType findMin(PriorityQueue h){    if (h->size > 0) {        return h->elements[1];    }    return kMinSentinelElement;}//遍历void traverse(PriorityQueue h){    int size = h->size;    for (int i = 0; (2*i) <= size; i++) {        if (i != 0) {            printf("the element is %d\n", h->elements[2*i]);        }        if (2*i+1 <= size) {            printf("the element is %d\n", h->elements[2*i + 1]);        }    }    printf("\n");        for (int i = 0; 2*i <= size; i++) {        if (i != 0) {            printf("the left element is %d\n", h->elements[2*i]);        }    }    printf("\n");    for (int i = 0; (2*i+1) <= size; i++) {        if (i != 0) {            printf("the right element is %d\n", h->elements[2*i+1]);        }    }    printf("\n");}void testInfoMessage(){    PriorityQueue priorityq = initialize(15);    insert(priorityq, 1);    traverse(priorityq);        insert(priorityq, 2);    insert(priorityq, 3);    insert(priorityq, 4);    insert(priorityq, 5);    //    insert(priorityq, 2);//    insert(priorityq, 4);//    insert(priorityq, 3);//    insert(priorityq, 5);    //    insert(priorityq, 4);//    insert(priorityq, 8);//    insert(priorityq, 12);//    insert(priorityq, 11);    //    insert(priorityq, 4);//    insert(priorityq, 8);//    insert(priorityq, 12);//    insert(priorityq, 3);//    insert(priorityq, 7);//    insert(priorityq, 6);//    insert(priorityq, 5);//    insert(priorityq, 1);//    insert(priorityq, 9);        traverse(priorityq);        deleteMinFunction1(priorityq);    traverse(priorityq);        findTail(priorityq);        deleteMinFunction1(priorityq);    traverse(priorityq);        deleteMinFunction1(priorityq);    traverse(priorityq);        int arrNew[] = {49, 38, 65, 97, 26, 13, 27, 49, 55, 4};//    int arrNew[] = {49, 38, 65, 97, 26, 13, 27, 55, 4};        heapSort(arrNew, sizeof(arrNew)/sizeof(int));}//堆排序void heapSort(int arr[], int length){    //根据数组创建堆    #if 0 - 逐个插入    PriorityQueue priorityq = initialize(length);        for (int i = 0; i < length; i++) {        insert(priorityq, arr[i]);    }        traverse(priorityq);#endif    #if 1 - 逐渐向下过滤    PriorityQueue priorityq = initialize(length);        for (int i = 0; i < length; i++) {        priorityq->elements[i+1] = arr[i];    }    priorityq->size = length;        traverse(priorityq);        for (int i = length / 2; i > 0; i--) {        percolateDown(priorityq, i);    }        traverse(priorityq);#endif        for (int i = 0; i < length; i++) {        ElementType element = findMin(priorityq);        arr[i] = element;        //deleteMin(priorityq);        deleteMinFunction1(priorityq);//        deleteMinByFunction2(priorityq);    }        for (int i = 0; i < length; i++) {        printf("the arr[%d] is %d\n", i, arr[i]);    }}


原创粉丝点击