堆排序原理及c语言实现
2013-11-30 11:05
260 查看
很多同学在开始学排序算法的时候都会觉得堆排序是比较难的,其实对于堆排序,只要理解了两点,应该就可以掌握堆排序了,下面说说要理解哪两点以及c语言的实现。
第一点:堆的特性。
下面的堆的特性定义来自算法导论:
最大堆特性是指除了跟以外的每个结点i,有A[PARENT[i]]>=A[i],即每个结点的值至多是和其父结点的值一样大。
最小堆特性是指出了跟以外的每个结点i,有A[PARENT[i]]<=A[i],即每个结点的值至少是和其父结点的值一样大。
也就是说,最大堆的父结点都大于等于其子结点,最小堆的父结点都小于等于其子结点。
第二点:数组下标和堆结点的关系。
对于有n个元素的数组a
,其下标和堆结点的关系为:
父结点a[parent]的左右子结点分别是a[parent*2+1],a[parent*2+2], 0<= parent <= n/2-1;
数组下标从大到小看,下标为n/2-1的结点为堆的第一个非叶子结点。
假设我们现在有一个数组a[10] = {4,1,3,2,16,9,10,14,8,7},对应的二叉树为:
树结点外的数字就是该结点对应的数组下标。
跟结点4的下标为0,其左子结点1的下标为1,1 = 0 * 2 + 1;
其右子结点3的下标为2,2 = 0 * 2 + 2;
1的左子结点2的下标,3 = 1 * 2 + 1;右子结点16的下标 4 = 1 * 2 + 2;
3的左子结点9的下标,5 = 2 * 2 + 1; 右子结点10的下标 6 = 2 * 2 + 2;
2的左子结点14的下标,7 = 3 * 2 + 1;右子结点8的下标 8 = 3 * 2 + 2;
16的左子结点7的下标,9 = 4 * 2 + 1;
以最大堆为例,堆排序的过程就是将数组建立成一个最大堆,每次把跟结点取出来,就是最大的一个数,所以遍历完整个数组后,其算法复杂度就是O(n)*O(logn),其中O(n)是遍历数组的算法复杂度,O(logn)是调整堆的算法复杂度。
下面是c语言的实现:
第一点:堆的特性。
下面的堆的特性定义来自算法导论:
最大堆特性是指除了跟以外的每个结点i,有A[PARENT[i]]>=A[i],即每个结点的值至多是和其父结点的值一样大。
最小堆特性是指出了跟以外的每个结点i,有A[PARENT[i]]<=A[i],即每个结点的值至少是和其父结点的值一样大。
也就是说,最大堆的父结点都大于等于其子结点,最小堆的父结点都小于等于其子结点。
第二点:数组下标和堆结点的关系。
对于有n个元素的数组a
,其下标和堆结点的关系为:
父结点a[parent]的左右子结点分别是a[parent*2+1],a[parent*2+2], 0<= parent <= n/2-1;
数组下标从大到小看,下标为n/2-1的结点为堆的第一个非叶子结点。
假设我们现在有一个数组a[10] = {4,1,3,2,16,9,10,14,8,7},对应的二叉树为:
树结点外的数字就是该结点对应的数组下标。
跟结点4的下标为0,其左子结点1的下标为1,1 = 0 * 2 + 1;
其右子结点3的下标为2,2 = 0 * 2 + 2;
1的左子结点2的下标,3 = 1 * 2 + 1;右子结点16的下标 4 = 1 * 2 + 2;
3的左子结点9的下标,5 = 2 * 2 + 1; 右子结点10的下标 6 = 2 * 2 + 2;
2的左子结点14的下标,7 = 3 * 2 + 1;右子结点8的下标 8 = 3 * 2 + 2;
16的左子结点7的下标,9 = 4 * 2 + 1;
以最大堆为例,堆排序的过程就是将数组建立成一个最大堆,每次把跟结点取出来,就是最大的一个数,所以遍历完整个数组后,其算法复杂度就是O(n)*O(logn),其中O(n)是遍历数组的算法复杂度,O(logn)是调整堆的算法复杂度。
下面是c语言的实现:
void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } void buildMaxHeap(int a[], int parentIndex, int lastIndex) { int left; int right; int max; left = parentIndex * 2 + 1; /* 左子结点下标 */ right = parentIndex * 2 + 2; /* 右子结点下标 */ while (left <= lastIndex) { max = left; /* 先假设左子结点为最大 */ /* 如果存在右子结点 */ if (right <= lastIndex) { if (a[left] < a[right]) { max = right; /* 右子结点比左子结点要大 */ } } /* 如果父结点比子结点要小,那么子结点上升为父结点, * 原先的父结点下降为子结点,继续重复调整 */ if (a[parentIndex] < a[max]) { swap(&a[parentIndex], &a[max]); parentIndex = max; } else { return; /* 父结点比子结点都大,符合最大堆的特性,返回 */ } /* 继续往下调整 */ left = parentIndex * 2 + 1; right = parentIndex * 2 + 2; } } /* n是数组元素的个数 */ void heapSort(int a[], int n) { int i; int unsort; /* 先将数组建立成一个最大堆*/ for (i = n / 2 - 1; i >= 0; i--) { /* 从最后一个非叶子结点开始调整 */ buildMaxHeap(a, i, n - 1); } swap(&a[0], &a[n - 1]); /* 遍历数组,每次取一个最大的,然后调整堆 */ for (unsort = n - 1; unsort > 0; unsort--) { buildMaxHeap(a, 0, unsort-1); swap(&a[0], &a[unsort-1]); } } int main() { int i; int a[] = {4,1,3,2,16,9,10,14,8,7}; heapSort(a, 10); for (i = 0; i < 10; i++) { printf("%d ", a[i]); } printf("\n"); return 0; }
相关文章推荐
- 数据结构排序算法之堆排序(c语言实现)
- 堆排序原理及算法实现(最大堆)
- c语言可变参数原理以及printf函数的自实现
- 堆排序(Heap Sort)原理及Java实现
- 位图排序原理及C语言实现(源于《编程珠玑》)
- CRC算法原理及C语言实现(转)
- C语言中可变参数函数实现原理
- CRC算法原理及C语言实现(介绍了3种方法)
- 排序算法的C语言实现-堆排序
- 经典算法: 堆排序的原理和实现, 建立堆,调整堆
- C语言实现 排序源程序(包括直接插入、希尔、冒泡、快速、简单选择、堆排序)
- C语言可变参数函数实现原理
- P2P通信原理与实现(C语言)
- C语言对堆排序一个算法思路和实现代码
- 高斯滤波原理及C语言实现
- 堆排序及其c语言实现
- 堆排序的c语言实现
- C语言可变长参数实现原理
- 程序员面试题--堆排序的C语言实现
- c语言中-x的实现原理