堆排序详解
来源:互联网 发布: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]); }}
阅读全文
0 0
- 排序详解:堆排序
- 排序详解:堆排序
- [转]堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序算法详解
- 堆排序算法详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序图片详解
- 堆排序详解
- 堆排序算法详解
- 堆排序详解
- 将罗马数字转化为整数
- 树莓派学习随笔(一)
- U-Boot启动过程完全分析
- Android开发之Paint的高级使用
- bootstrap的简单用法
- 堆排序详解
- VBA取得EXCEL表格中的行数和列数
- 在Oracle数据库中用到的函数
- LeetCode: 2 Sum
- 解决iframe,div在移动设备上实现局部刷新的方法
- Eclipse 4.7 Oxygen重大更新前瞻
- 代码1
- IOS 上传App
- spring 结合 Redis 例子,简单入门例子