堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:
Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]
即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。
堆分为大顶堆和小顶堆:
大顶堆 小顶堆
算法思想(以大顶堆为例):
1.将长度为n的待排序的数组进行堆有序化构造成一个大顶堆(将数组--》转化为一个大顶堆)
2.将根节点与尾节点交换并输出此时的尾节点(交换节点)
3.将剩余的n -1个节点重新进行堆有序化(交换节点后继续有序化)
4.重复步骤2,步骤3直至构造成一个有序序列(重复2,3步骤)
假设待排序数组为[20,50,10,30,70,20,80]
具体程序实现:
public
class
HeapSort {
private
static
void
heapSort(
int
[] arr) {
int
len = arr.length -
1
; //记得-1
for
(
int
i = len/
2
-
1
; i >=
0
; i --){
//堆构造,将数组转换为大顶堆
heapAdjust(arr,i,len);
}
while
(len >=
0
){
swap(arr,
0
,len--);
//将堆顶元素与尾节点交换后,长度减1,尾元素最大
heapAdjust(arr,
0
,len);
//,别忘了这一步,再次对堆进行调整
}
}
public
static
void
heapAdjust(
int
[] arr,
int
i,
int
len){
int
left,right,j ;
while
((left =
2
*i+
1
) <= len){
//判断当前父节点有无左节点(即有无孩子节点,left为左节点)(注意是左节点,而不是右节点,下面才是右节点)
right = left +
1
;
//右节点
j = left;
//j"指针指向左节点"
if
(j < len && arr[left] < arr[right])
//判断右节点是否存在并且是否右节点大于左节点
j ++;
//当前把"指针"指向右节点====》下一行的巧妙处理,j不加1,则是与左节点比较,加一则是与右节点比较
if
(arr[i] < arr[j])
//将父节点与孩子节点交换(如果上面if为真,则arr[j]为右节点,如果为假arr[j]则为左节点)
swap(arr,i,j);
else
//说明比孩子节点都大,直接跳出循环语句
break
;
i = j; // 子节点与父节点交换位置后,要重新进行堆调整,故将j的值赋予i;
}
}
public
static
void
swap(
int
[] arr,
int
i,
int
len){//交换两个数
int
temp = arr[i];
arr[i] = arr[len];
arr[len] = temp;
}
public
static
void
main(String[] args) {//测试部分
int
array[] = {
20
,
50
,
20
,
40
,
70
,
10
,
80
,
30
,
60
};
System.out.println(
"排序之前:"
);
for
(
int
element : array){
System.out.print(element+
" "
);
}
heapSort(array);
System.out.println(
"\n排序之后:"
);
for
(
int
element : array){
System.out.print(element+
" "
);
}
}
}
看完不懂可参考https://www.cnblogs.com/MOBIN/p/5374217.html