一、选择排序
1、堆的定义:堆实际上是一棵完全二叉树,完全二叉树中所有非终端结点的值均不大于(或小于)其左、右子结点的值。只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。
2、大根堆:父结点的数据大于每一个子结点。
3、小根堆:每一个子结点的数据均大于父结点
4、父子结点转化:父结点: i 左右子树: j
父结点找子结点:——> 左子树:j = 2*i ; 右子树:j = 2*i+1
子结点找父结点: ——> 左子树:i = j/2 ; 右子树:i=j/2+1
5、堆排序思想:
利用大根堆(小根堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
6、基本过程:(大根堆为例)
(1)建堆:将初始数据按顺序依次建成堆。
(2)调整:将初始堆调整为大根堆(堆顶元素最大)。
(3)排序:将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(剩余元素组成的堆R1,R2,......Rn-1)和新的有序区(原大根堆堆顶元素Rn),且满足R[1,2...n-1]<=R[n]。
(4)由于交换后新的堆可能违反大根堆的性质,所以需要进行调整。然后再次将堆顶元素R[1]与最后一个元素交换,得到新的无序区(R1,R2,......Rn-2),新的有序区(Rn-1,Rn)。重复此过直到有序区的元素为n-1,剩下最后一个元素为最小数字,则整个大根堆升序排序过程完成。
7、小根堆堆顶为最小的数字,经过建堆、调整等过程每次将堆顶元素和最后一个结点的数字交换经过排序后完成小根堆降序排序。
8、大根堆排序代码如下:
#include<stdio.h>
void HeapAdjust(int arr[], int i, int len)
{
int j; //j 左子树 j <= len:有左子树 j = len; 有左 没右 j < len:左右都有
for (j = 2 * i; j <= len; j = 2 * j)
{
if (j < len && arr[j] < arr[j + 1])
{
j++;
}
if (arr[j] < arr[i])break;
arr[0] = arr[i];
arr[i] = arr[j];
arr[j] = arr[0];
i = j;
}
}
void HeapSort(int arr[], int len)
{
int tmp;
for (int i = len / 2; i > 0; --i)
{
HeapAdjust(arr,i,len); //i 当前要调整的堆的父节点下标 len 有效长度
}
for (int j = len; j > 0; --j)
{
tmp = arr[1];
arr[1] = arr[j];
arr[j] = tmp;
HeapAdjust(arr, 1, j-1);
}
}
int main()
{
int arr[] = {-1,546, 326, 56, 4, 6, 23, 623, 9, 78, 989, 15, 1, 10 };
int len = sizeof(arr) / sizeof(arr[0])-1;
HeapSort(arr, len);
for(int i=0;i<=len;i++)
{
printf("%d ",arr[i]);
}
return 0;
}