赞
踩
给定一个有n个数据的数组,将其排列为升序或者降序。
//这里是下面用的到的升降序排序函数代码 //向下排序 void AdjustDown(int* a, int n, int parent) { assert(a); int child = parent * 2 + 1; while (child < n) { if (child + 1 < n && a[child] < a[child + 1]) // 如果建立小堆这里应变为> child++; if (a[child] > a[parent]) // 如果建立小堆这里应变为< { int tmp = a[parent]; a[parent] = a[child]; a[child] = tmp; parent = child; child = parent * 2 + 1; } else break; } } //向上排序 void AdjustUp(int* hp, HeapDataType child) { assert(hp); int parents = (child - 1) / 2; while (child) { if (hp[child] > hp[parents]) // 如果建立小堆这里应变为< { HeapDataType tmp = hp[parents]; hp[parents] = hp[child]; hp[child] = tmp; child = parents; parents = (child - 1) / 2; } else break; } }
这里以升序为例
1.建小堆,排升序。
①将数组的第一个元素看做堆,后面的数据依次加上堆,然后用向上调整构造小堆。
void AdjustUp(int* a, int n)
{
assert(a);
int i = 0;
for (i = 1; i < n; i++)
{
AdjustUp(a, i);
}
}
②倒着走找第一个父节点,然后对这个父节点向下调整,保证它下面的子树都是小堆。
叶节点的子树不需要调整,因为他本身就是小堆;所以从倒着走的第一个非叶节点的子树开始调整。
void AdjustUp(int* a, int n)
{
assert(a);
//找出第一个父节点
int i = (n - 1 - 1) / 2;
for (int k = i; k >= 0; k--)
{
AdjustDown(a, n, k);
}
}
但是这两种方法只可以将当前的数组列为小堆,只能选出最小的数,而次小的数则找不出来。从第二个位置开始看做堆,但这之前建立的关系全都乱了,只能重新建堆,才能找出次小的数,这样一来很麻烦。所以我们可以换一种思路。
2.排升序,建大堆
①利用上两个方法将当前的数组建成大堆,选出最大的数
②最大的数跟最后一个数交换
③最后一个数不看做堆内元素进行向下调整,即可选出次大的数
以此类推重复,时间复杂度为NlogN
注意:这里的AdjustUp和AdjustDown已经和上面的不同,父子节点关系已经改变
void HeapSort(int* a, int n) { assert(a); //建立大堆 int i = (n - 1 - 1) / 2; for (int k = i; k >= 0; k--) { AdjustDown(a, n, k); } for (int i = n - 1; i > 0; i--) { //将第一个元素和最后一个互换 int tmp = a[0]; a[0] = a[i]; a[i] = tmp; //不看最后一个元素向下调整 AdjustDown(a, i, 0); //注意此处i既是最后一个元素的下标,又是删除最后一个元素后前面元 //素的个数,所以传i就代表了不看最后一个元素 } }
如果要排成降序,那么只需要改变AdjustDown和Adjustup内父子元素的关系即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。