基本思想:先将待排序数据化为完全二叉树,从length/2+1处开始寻找他的左/右子节点,将较大值与父节点进行交换,最后遍历到根节点处,此时根节点为所有数中的最大值,将该值与最后一个元素进行交换,length=length-1,又从父节点开始进行比较,继续寻找较大值。将找到的较大值与length-2处进行交换。依次类推。
1.首先将待排序的数组元素转换为完全二叉树,根节点对于数组第一个元素,按先序遍历进行排序,即根节点,左子节点,右子节点。
2.待排序数组长度为length=8,首先进行堆的初始化,定义一个for循环for(i=length/2-1;i>0;i--)。i首先等于8/2-1=3;因此从a[3]处作为父节点,寻找比它大的左右子节点。此时6作为父节点,3作为左子节点,6没有右子节点,6是最大值因此不需要进行交换。进入下一轮for循环
3.i此时等于2。因此a[2]处作为父节点,它的左子节点右子节点分别为6和1,6比4大,此时最大值位置max=2*2+1处,1比4小,max位置仍为2*2+1处,因此交换a[2]与a[2*2+1]处的元素。交换完成后a[5]作为父节点继续寻找它的左右子节点,此时a[5]已经为叶子节点,没有子节点,因此该轮循环结束。
4.i此时等于1。因此a[1]处作为父节点,它的左子节点右子节点分别为6和7,5<6,max位置为3处。5<7,max位置变为4。因此交换a[1]与a[max]处的元素。交换后5变为右子节点,此时5已经是叶子节点因此不需要进行继续寻找子节点,该轮循环结束。
5.i此时等于0。因此a[0]处作为父节点,它的左子节点右子节点分别为7和6,7<12,6<12,max位置为0。此轮循环结束,i变为-1循环结束。此时父节点为数组中的最大值。
6.进入另外一个循环for(i = len - 1; i >=0; i--),该循环将栈顶元素与最后一个元素进行交换。i=7,将a[0]与a[7]进行交换。
7.此时又从栈顶开始,a[0]作为父节点,比较左右子节点。7>3,max=1。交换a[1]和a[0]。
7.交换的元素a[1]不是叶子节点,需要继续迭代进行交换。保证交换的元素比它子节点大。因此将a[1]与a[3]进行交换。12作为最大元素不在参与上面的交换。此时7作为最大值位于父节点处。
8.将该循环将栈顶元素与最后一个元素进行交换。此时最后一个元素为a[length-2]。即7与1进行交换。
9.交换后i=length-1;又从a[0]开始继续迭代比较。将1和左子节点的6进行交换。交换后继续将1作为父节点和它的右子节点5进行交换。
10.当i<0时,排序完成。
代码:
//list:待调整的数组 index:待调整的节点下标 len:数组长度
void HeapAdjust(int list[], int index, int len)
{
int max = index;//保存父节点下标
int lchild = index * 2 + 1;//下标从0开始
int rchild = index * 2 + 2;//下标从0开始
//左子节点大于父节点
if (lchild<len&&list[lchild]>list[max])
{
max = lchild;
}
//右子节点大于父节点
if (rchild<len&&list[rchild]>list[max])
{
max = rchild;
}
if (max!=index)
{
swap(list[max], list[index]);
HeapAdjust(list, max, len);
}
}
//初始化堆,大顶堆,从小到大
void HeapSort(int list[], int len)
{
//初始化堆
for (int i = len / 2 - 1; i >= 0; i--)
{
HeapAdjust(list, i, len);
}
//交换堆顶元素和最后一个元素
for (int i = len - 1; i >=0; i--)
{
swap(list[0],list[i]);
HeapAdjust(list, 0, i);
}
}
int main()
{
int list[] = { 12, 5, 4, 6, 7, 6, 1 ,3};
HeapSort(list, sizeof(list) / sizeof(int));
for (int i = 0; i < sizeof(list) / sizeof(int); i++)
{
cout << list[i] << endl;
}
}
堆排序是一种不稳定的排序方法,最好、最坏、平均时间复杂度:,空间复杂度为