堆排序算法思想
堆是一颗二叉树,这样的二叉树是局部有序的,任何节点与其兄弟节点之间都没有必然的顺序联系,但是它与父子节点之间有大小顺序关系,按照关系的不同,分为最大值堆和最小值堆
最大值堆:子节点比父节点小的堆,根节点是树中最大的节点。
最小值堆:子节点比父节点大的堆,根节点是树中最小的节点。
堆排序的两种调整方法:向下调整、向上调整,实现堆排序就要理解物理到逻辑映射关系
- 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
- 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
- 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
下面实现主要是关于堆排序的降序实现:
堆排序的具体实现
//堆排序 最小堆,根节点小于左右孩子节点
void PrintInt(int* ar, int n)
{
for (int i = 0; i < n; i++)
{
printf("%5d", ar[i]);
}
printf("\n");
}
void FilerDown(int* nums, int strat, int end) //向下调整
{
int i = strat ;
int j = i * 2 + 1;
int temp = nums[i];
while (j<=end)
{
if (j<end&&nums[j] > nums[j + 1])j += 1; //找左孩子和右孩子谁最小,将最小值赋值给j
if (temp <= nums[j])break;
nums[i] = nums[j];
i = j;
j = i * 2 + 1;
}
nums[i] = temp;
}
void HeapSort(int* nums, int n)
{
if (nullptr == nums || n < 2)return;
int pos = (n - 2) / 2;
while (pos >= 0)
{
FilerDown(nums, 0, n - 1); //调整,从最下面进行调整
--pos;
}
pos = n - 1;
while (pos > 0)
{
std::swap(nums[0], nums[pos]); //交换,将最小的值放入数组后面
--pos;
FilerDown(nums, 0, pos);
}
}
void FilerUp(int* nums, int start) //向上调整
{
int j = start, i = (j - 1) / 2;
int temp = nums[j];
while (j > 0)
{
if (nums[i] <= temp)break;
nums[j] = nums[i];
j = i;
i = (j - 1)/2;
}
nums[j] = temp;
}
int main()
{
int ar[] = { 53,17,78,9,45,65,87,23 };
int n = sizeof(ar) / sizeof(ar[0]);
PrintInt(ar, n);
HeapSort(ar, n);
PrintInt(ar, n);
}