《算法导论》学习笔记(1)——堆与堆排序
来源:互联网 发布:什么是node服务器 编辑:程序博客网 时间:2024/06/06 18:53
堆排序( Heapsort )是指利用“堆”这种数据结构所设计的一种排序算法。
堆是一种数据结构,是一个数组。它可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除了最底层外,即叶子结点,该树是完全充满的,而且是从左到右填充。
最大堆的每个结点都要满足堆的性质,此外还有其他的约束:堆中的最大元素存放在根结点中,并且在任一子树中,该子树所包含的所有结点的值都不大于该子树根结点的值。
堆排序就是利用最大堆的性质来排序。大致步骤如下:
①建最大堆
②将根结点(最大元素)与最后一个结点的元素互换,并将剩下的结点维护最大堆的性质。
③重复步骤②,直到将每个元素排完序。
下面就讲解几个重要过程:
维护最大堆的性质:MaxHeapify
传入参数:待排序数组、需要维护的下标、当前堆的大小。返回值:空
每次在传入参数的下标、该下标的左、右孩子结点三者中选出最大的元素。如果最大元素是该下标,则满足最大堆性质,结束。否则,需要将父亲与最大的孩子交换位置,使得当前下标及其左右孩子满足最大堆的性质。之后递归调用,使得整个子树都满足最大堆的性质。
特别需要注意,数组的大小和堆的大小是不一样的概念。堆的大小表示有多少个堆元素存储在数组中。在进行堆排序的过程中,每次需要把根结点元素与最后一个元素交换,这样堆的大小每次就会减一。而数组大小是不会变的。也就是:
0 ≤ 堆的大小 ≤ 数组的大小
建最大堆:BuildMaxHeap
传入参数:待排序数组、当前堆的大小。返回值:空
只需保证所有的非叶子结点满足最大堆的性质即可。非叶子结点的下标为从0到堆大小 / 2(向下取整)。
堆排序:HeapSort
传入参数:待排序数组、当前堆的大小。返回值:空
首先建堆,然后每次去除根结点元素(最大元素),然后维护最大堆的性质。如此循环,直到所有元素排序完毕。
实现代码如下:
#include <iostream>using namespace std;typedef int ElemType;int getLeftChild( int i ) //返回左孩子下标。注:数组从位置0开始{return 2 * i + 1;}int getRightChild( int i ) //返回右孩子下标。注:数组从位置0开始{return 2 * i + 2;}void swap( ElemType *a, ElemType *b ) //交换两个元素{ElemType temp = *a;*a = *b;*b = temp;}/* 维护最大堆的性质。 * 参数:待排序数组、需要维护的下标、当前堆的大小 * 返回值:空 */void MaxHeapify( ElemType *A, int i, int num ){int left = getLeftChild( i );int right = getRightChild( i );int largest; // 存放父结点、左右子节点三者的最大值的下标位置if( left <= num && A[left] > A[i] )largest = left;elselargest = i;if( right <= num && A[right] > A[largest] )largest = right;if( largest != i ){swap( &A[i], &A[largest] );MaxHeapify( A, largest, num );}}/* 建最大堆 * 传入参数:待排序数组、当前堆的大小 * 返回值:空 */void buildMaxHeap( ElemType *A, int num ){for( int i=num/2; i>=0; i-- )MaxHeapify( A, i, num );}/* 堆排序 * 待排序数组、当前堆的大小 * 返回值:空 */void heapSort( ElemType *A, int num ){buildMaxHeap( A, num-1 );int HeapSize = num - 1; //当前堆的大小for( int i=num-1; i>0; i-- ){swap( &A[0], &A[i] );HeapSize--;MaxHeapify( A, 0, HeapSize );}}int main(){ElemType A[10] = {1,3,6,2,4,8,0,9,7,5};heapSort( A, 10 );for( int j=0; j<10; j++ )cout << A[j] << " ";cout << endl;return 0;}
时空复杂度:
由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。
由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
堆排序是就地排序,辅助空间为O(1), 它是不稳定的排序方法。
- 《算法导论》学习笔记(1)——堆与堆排序
- 堆排序算法分析——《算法导论》学习笔记
- 算法导论学习笔记——堆排序
- 算法导论学习笔记(1)---堆排序
- 算法导论笔记——堆排序
- 学习算法导论——堆排序
- 算法导论学习笔记--2--堆排序
- 算法导论-堆排序学习笔记
- 堆排序-《算法导论》学习笔记六
- 算法导论学习笔记(三):堆排序
- 算法导论笔记,堆排序
- 算法导论学习笔记(一)排序算法之堆排序
- 跟着《算法导论》学习——堆排序
- 算法导论学习之——堆排序
- 《算法导论》学习摘要chapter-6——堆排序
- 堆排序(最小堆)--【算法导论】
- 数据结构与算法学习笔记——堆排序
- 算法导论—堆排序C++实现
- dsdsdsdsdsds
- WebBrowser控件: GeckoFX
- hdu——1281——棋盘游戏
- app后端设计(7)-- 项目管理
- 网络协议
- 《算法导论》学习笔记(1)——堆与堆排序
- 路径查找基础知识-动画演示
- SQL 数据库 试题精华大全
- iOS 新特性
- 九度oj 题目1024:畅通工程
- [POJ 3164] Command Network 有向图的最小树形图(朱刘算法)
- Dedecms网站地图获取文章列表支持标签调用
- c++ 链表操作:添加、遍历、删除、查找
- Cortex-AX系列性能对比