活动地址:CSDN21天学习挑战赛
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
堆是一种树形选择排序方法,它的特点是将一个序列看成是一个二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的位置关系在无序区中选择关键字最大(或最小)的元素;
- 下面是一个大根堆的建立过程;
- 首先找到第一个非叶子结点,将其单独看成一颗二叉树,再与其两个孩子结点进行对比,如果孩子结点比它大,则将最大的孩子结点跟它进行交换位置;
- 当前子树排序完毕后,再寻找下一个非叶子结点继续排序,直到整颗树的非叶子都进行了排序,则第一趟排序结束;
- 堆排序的排序有可能进行一趟就排序完毕,但是最差情况下需要进行 ( log₂ N )+ 1 次排序,因为最差情况下可能每趟排序只能将一层元素放置在其最终的位置;( N 为 非叶子结点的个数 ,前面的层数有序了,最后一层也自然会有序了 )
- 首先建立一个数组存储待排序的序列;
- 建立一个变量存储最大非结点的坐标位置,因为数组的坐标是从 0 开始的,所以寻找最大非叶子结点坐标的时候需要用长度减去 1 再除 2 ( 堆顶坐标为 1 的时候,所有结点的左孩子结点等于 2 倍自身坐标值,右孩子坐标等于 2 倍自身坐标值 + 1 );
- 建立一个变量确定除叶子结点外的层数,因为完全二叉树的层数等于( log₂ N )+ 1( N 结点数 ),又因为 num 为最大非叶子结点的坐标,故除叶子结点外的层数等于 ( log₂ num+1 )+ 1;
- 确定了层数就确定循环次数,再在循环内写入排序的方法,排序的方法有两个参数,一个是待排序的数组,一个是排序的起始位置( 也就是第一个非叶子结点 );
- 建立一个变量存储数组的长度;
- 建立一个循环遍历每一个非叶子结点;
- 建立一个变量存储当前子树的最大结点的坐标,赋初值为父结点坐标;
- 建立两个变量分别存储该子树的左右孩子结点坐标( 因为用数组存储,数组初始坐标为 0 ,故计算左孩子坐标时为 i * 2 + 1 ,而右孩子就在左孩子的右边一个单元故右孩子坐标为左孩子坐标 + 1 );
- 如果左孩子坐标未超出最大坐标并且左孩子的值大于所存储结点的值,那么将左孩子的坐标拷贝至存储最大元素坐标的辅助空间;
- 如果右孩子坐标未超出最大坐标并且左孩子的值大于所存储结点的值,那么将右孩子的坐标拷贝至存储最大元素坐标的辅助空间;
- 如果存储最大元素坐标的辅助变量被改变过,那么将所记录的坐标的值跟父结点的值进行交换;
- 至此堆排序功能已完成;
- 除了上述确定循环次数的方法,还有利用递归的方法;
- 首先在方法传值时增加一个传入最大需要遍历到的树顶坐标;
- 再在判断是否需要交换的语句末尾增加一条递归,递归时将当前子树树顶作为最大遍历到的结点,受更改的结点作为起始遍历坐标;
public class test {
public static void main(String[] args){
int[] arr = { 8 , 14 , 25 , 16 , 24 , 17 ,28 };
int num = (arr.length - 1) / 2;
int n = (int)(Math.log( num + 1 ) / Math.log( 2 )) + 1;
for (int i = 0; i < n; i++) {
heapsort( arr , num );
}
for ( int e : arr ) {
System.out.print( e + " " );
}
}
public static void heapsort( int[] arr , int num ) {
int len = arr.length;
for (int i = num; i >= 0; i--) {
int max = i;
int left = i * 2 + 1;
int right = left + 1;
if ( left < len && arr[left] > arr[max] )
max = left;
if ( right < len && arr[right] > arr[max] )
max = right;
if ( max != i ){
int temp = arr[i];
arr[i] = arr[max];
arr[max] = temp;
}
}
}
}
public class test {
public static void main(String[] args){
int[] arr = { 8 , 14 , 25 , 16 , 24 , 17 ,28 };
int num = (arr.length - 1) / 2;
int n = (int)(Math.log( num + 1 ) / Math.log( 2 )) + 1;
heapsort( arr , 0 , num );
for ( int e : arr ) {
System.out.print( e + " " );
}
}
public static void heapsort( int[] arr , int n , int num ) {
int len = arr.length;
for (int i = num; i >= n; i--) {
int max = i;
int left = i * 2 + 1;
int right = left + 1;
if ( left < len && arr[left] > arr[max] )
max = left;
if ( right < len && arr[right] > arr[max] )
max = right;
if ( max != i ){
int temp = arr[i];
arr[i] = arr[max];
arr[max] = temp;
heapsort( arr , i , temp );
}
}
}
}