面试题
要求:
写一个堆排序算法
不限语言
#include <iostream>
using namespace std;
void percDown(int *q, int l, int r) {
int i = l, j = 2 * i + 1;
while(j <= r) {
if(j + 1 <= r && q[j] < q[j + 1]) j = j + 1;
if(q[i] < q[j]) swap(q[i], q[j]);
else break;
i = j, j = 2 * j + 1;
}
}
void buildHeap(int *q, int len) {
for(int i = len / 2; i >= 0; i--)
percDown(q, i, len - 1);
}
void heapSort(int *q, int len) {
while(len--) {
swap(q[0], q[len]);
percDown(q, 0, len - 1);
}
}
int main() {
int q[] = {5, 1, 10, 7, 2, 3, 0};
int len = sizeof(q) / sizeof(int);
buildHeap(q, len);
heapSort(q, len);
cout << endl;
for(int i = 0; i < len; i++)
cout << q[i] << endl;
return 0;
}
一 准备知识
堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆
-
算法思想
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 -
实现原理
要实现从小到大的排序,就要建立大顶堆,即父节点比子节点都要大。
2.1、初始化数组,创建大顶堆。
1. 大顶堆的创建从下往上比较,不能直接用无序数组从根节点比较,否则有的不符合大顶堆的定义。
2.2、交换根节点和倒数第一个数据,现在倒数第一个数据就是最大的。
2.3、重新建立大顶堆。
1. 因为只有 array[0] 改变,其它都符合大顶堆的定义,所以可以根节点 array[0] 重新建立。
2.4、重复2.2、2.3的步骤,直到只剩根节点 array[0],即 i=1。
主要思路:第一次保证00位置大根堆结构(废话),第二次保证01位置大根堆结构,第三次保证02位置大根堆结构…直到保证0n-1位置大根堆结构(每次新插入的数据都与其父结点进行比较,如果插入的数比父结点大,则与父结点交换,否则一直向上交换,直到小于等于父结点,或者来到了顶端)
三 总结
1、首先将无需数组构造成一个大根堆(新插入的数据与其父结点比较)
2、固定一个最大值,将剩余的数重新构造成一个大根堆,重复这样的过程