C语言算法系列:堆排序
2013-10-29 21:45
211 查看
我发现自己把数据结构和算法里的很多内容都忘了,今天面试的时候面试官问我堆排序,我居然没有完整地回答出来。看来这些基础知识还是很重要的,所以我打算从今天开始复习,为以后找工作做准备。
总结一下算法的主要思想,不能下次别人问的时候又不知道了。以从小到大排序为例,堆排序的重点分为两步:
1)建立一个初始的大顶堆;
2)现在最大的元素在堆顶arr[0],将它和最末尾的元素arr[size]交换位置,这样最大的元素arr[0]就移动到了数组的最末尾。再将大顶堆的规模size减一,对前size个元素继续建大顶堆,那么第二大的元素到了堆顶arr[0],将它与arr[size]交换位置,这样第二大的元素就移动到了数组的倒数第二末尾...重复这个过程,直到所有元素都排好序。
那么难点就在怎么样建造这个大顶堆呢?我们构造maxheapify这个函数,它的作用就是:对于i∈[size/2-1, 0],比较某个元素i和它的两个子节点2i+1, 2i+2的关系,在这三个节点不满足大顶堆的性质时进行上下节点的位置调整,以保持大顶堆的性质。如果发生了元素位置的调换,那么可能调换部分的子树也需要重新调整,所以递归地调用maxheapify,从上往下逐步调整为大顶堆。
本算法用C语言根据《算法导论(第二版)》中的思想写成。
进阶知识:一道常见的面试题,在n个数中找出最大的m个数。当m<<n时,这个问题就可以用堆排序来做。
先对前m个数建一个小顶堆,对于剩下的数i(i∈[m+1,n])进行遍历:如果i大于堆顶元素,那么将i与堆顶的元素互换,重新调整小顶堆。
在遍历完成后,这个堆中剩下的m个数就是最大的m个数啦。
算法的关键就是维护这个小顶堆,找出当前较大的m个数,且保持“最危险的优势”的那个元素,即堆里最小的那个元素在堆顶,便于下一步的比较。
算法复杂度是O(nlgm)。遍历O(n),建堆O(lgm)。
总结一下算法的主要思想,不能下次别人问的时候又不知道了。以从小到大排序为例,堆排序的重点分为两步:
1)建立一个初始的大顶堆;
2)现在最大的元素在堆顶arr[0],将它和最末尾的元素arr[size]交换位置,这样最大的元素arr[0]就移动到了数组的最末尾。再将大顶堆的规模size减一,对前size个元素继续建大顶堆,那么第二大的元素到了堆顶arr[0],将它与arr[size]交换位置,这样第二大的元素就移动到了数组的倒数第二末尾...重复这个过程,直到所有元素都排好序。
那么难点就在怎么样建造这个大顶堆呢?我们构造maxheapify这个函数,它的作用就是:对于i∈[size/2-1, 0],比较某个元素i和它的两个子节点2i+1, 2i+2的关系,在这三个节点不满足大顶堆的性质时进行上下节点的位置调整,以保持大顶堆的性质。如果发生了元素位置的调换,那么可能调换部分的子树也需要重新调整,所以递归地调用maxheapify,从上往下逐步调整为大顶堆。
本算法用C语言根据《算法导论(第二版)》中的思想写成。
#include "iostream" using namespace std; void swap(int *a, int *b); void maxheapify(int arr[], int root, int size); void heapsort(int arr[], int size); void heapbuild(int arr[], int root, int size); int arrsize = 11; int main() { int arr[11] = {-4,4,27,-10,5,9,61,90,354,87,3}; heapsort(arr, arrsize); for(int i = 0; i < arrsize; i++) cout << arr[i] << " "; getchar(); } void swap(int &a, int &b) { int temp; temp=a; a=b; b=temp; } void maxheapify(int arr[], int root, int size) { int lchild = root * 2 + 1; int rchild = root * 2 + 2; int largest = root; if(arr[root] < arr[lchild] && lchild <= size) { largest = lchild; } if(arr[largest] < arr[rchild] && rchild <= size) { largest = rchild; } if(largest != root) { swap(arr[largest], arr[root]); maxheapify(arr, largest, size); } } void heapbuild(int arr[], int root, int size) { for(int i = size/2 -1; i >= 0; i--) { maxheapify(arr, i, size); } } void heapsort(int arr[], int size) { heapbuild(arr, 0, size); for(int i = size-1; i >= 2; i--) { swap(arr[0],arr[i]); heapbuild(arr, 0 , i-1); } swap(arr[0],arr[1]); }
进阶知识:一道常见的面试题,在n个数中找出最大的m个数。当m<<n时,这个问题就可以用堆排序来做。
先对前m个数建一个小顶堆,对于剩下的数i(i∈[m+1,n])进行遍历:如果i大于堆顶元素,那么将i与堆顶的元素互换,重新调整小顶堆。
在遍历完成后,这个堆中剩下的m个数就是最大的m个数啦。
算法的关键就是维护这个小顶堆,找出当前较大的m个数,且保持“最危险的优势”的那个元素,即堆里最小的那个元素在堆顶,便于下一步的比较。
算法复杂度是O(nlgm)。遍历O(n),建堆O(lgm)。
相关文章推荐
- 白话经典算法系列之七 堆与堆排序
- 排序系列- 堆排序
- 源码系列:堆排序、优先队列
- 排序总结系列七:堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序
- 重学数据结构系列之——堆及堆排序
- 经典算法系列三----堆排序
- 白话经典算法系列之七 堆与堆排序
- 排序算法系列-堆排序-快速排序-基数排序-简单选择排序-归并排序
- 白话经典算法系列之七 堆与堆排序
- 数据结构+算法系列四:I 堆排序
- 白话经典算法系列之七 堆与堆排序
- 算法实现系列第二章.堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序