ACM入门(2)——数据结构——堆排序
作为内部排序中的重要一员,堆排序是对简单排序中的“选择排序”的优化,常见的是以数组构造的完全二叉树,其结构列类似世界杯16强后的淘汰赛(想想各豪强的对决形势图),自顶向下每个节点往下至多有两个分支,其结构的优点是最优者不必与其它各队比较即可捧杯,这样即可将选择排序中逐个比较的缺点消除,时间复杂度由n级别降到log(n);排n个数即为O(n*log(n))。
对堆的操作主要是在末尾添加元素和取出堆顶元素,每次在堆尾添加元素后总要由此向上调整,保持堆的堆顶最优(最大或最小);同时每次取堆顶元素时,总是先将堆顶元素取出,然后将堆尾元素放在堆顶,接着从上往下进行比较调整,保持堆的结构。
每次总是从最后面插入元素,在最前面取出,同时保证取出的是最优元素,正是STL中优先队列的具体模型。
其代码实现如下:(C/C++)
int heap[1001];//建数组保存堆元素
int hlength;//保存堆的元素个数
void down(int p)
{
//向下调整算法,p代表当前节点,q代表子节点
int q=p*2;
int a=heap[p];//保存当前节点的值
while (q<=hlength)
{
if (q<hlength&&heap[q]>heap[q+1])
//选择两个子节点中的一个最小的
q++;
if(heap[q]>=a) break;//如果子节点比当前节点大,就结束
else//否则就交换
{
heap[p]=heap[q];
p=q;
q=p*2;
}
}
heap[p]=a;//安排原来的节点
}
void up(int p)
{
//向上调整算法,p代表当前节点,而q代表父母节点
int q=p/2;//获取当前节点的父母节点
int a=heap[p];//保存当前节点的值
while (q<=hlength&&a<heap[q])
{
//如果当前节点的值比父母节点的值小,就交换
heap[p]=heap[q];
p=q;
q=p/2;
}
heap[p]=a;//最后安排原来的节点
}
void insert(int a)
{
heap[++hlength]=a;//先往堆里插入节点值
up(hlength);//进行向上调整
}
int getmin()
{
//删除最小元素算法
int r=heap[1];//取出最小的元素
heap[1]=heap[hlength--];//然后把最后一个叶子节点赋给根节点
down(1);//调用向下调整算法
return r;
}
void build()
{
//建堆算法
for(int i=hlength/2;i>0;i--)
down(i); //从最后一个非终端节点开始进行调整
}
举个例子:
HDU 1058
Humble Numbers
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2570 Accepted Submission(s): 1077
Problem Description
A number whose only prime factors are 2,3,5 or 7 is called a humble number. The sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, ... shows the first 20 humble numbers. Write a program to find and print the nth element in this sequence
Input
The input consists of one or more test cases. Each test case consists of one integer n with 1 <= n <= 5842. Input is terminated by a value of zero (0) for n.
Output
For each test case, print one line saying "The nth humble number is number.". Depending on the value of n, the correct suffix "st", "nd", "rd", or "th" for the ordinal number nth has to be used like it is shown in the sample output.
Sample Input
1
2
3
4
11
12
13
21
22
23
100
1000
5842
0
Sample Output
The 1st humble number is 1.
The 2nd humble number is 2.
The 3rd humble number is 3.
The 4th humble number is 4.
The 11th humble number is 12.
The 12th humble number is 14.
The 13th humble number is 15.
The 21st humble number is 28.
The 22nd humble number is 30.
The 23rd humble number is 32.
The 100th humble number is 450.
The 1000th humble number is 385875.
The 5842nd humble number is 2000000000.
Tips:
思路为用2,3,5,7对堆初始化,然后每次从堆顶取出元素,将其的2,3,5,7倍放入堆中,然后动态排序,对上述测试数据可以看出:用一般方法要进行上千次的低级排序,效率之低,必会超时,那就辛苦了我们的CPU了。另外还要注意用64位long long来保存数据,防止溢出错误(20000000000已接近int的上界了)。