堆排序思想:
堆排序--升序采用大根堆 -----降序采用小根堆
1、将待排序序列构建成大根堆即:先要建立堆->建堆过程需要调整堆
2、此时,整个序列的最大值就是堆顶的根节点,将其与末尾的元素进行交换,此时末尾元素就是最大值
3、然后将剩余的n-1个元素构成一个堆,这样会得到n个元素的次小值,如此反复执行 便能得到一个有序序列了
细分步骤:
其实就是堆的初始化(过程中 调整堆)、交换第一个元素和最后一个元素、继续调整堆(是从最后一个非终端结点(n/2取下界) 开始往上调整)
上代码:
package Data.Structure.sort.select_sort;
public class heapSort {
public static void main(String[] args) {
//进行升序排序--即大根堆
int A[] = {4, 6, 8, 5, 9};
heapSort(A);
System.out.println(Arrays.toString(A));
}
/**
* 调整堆
* @param A 带调整的数组
* @param i 当前调整的双亲结点的编号,即非叶子结点在数组中的索引
* @param length
*/
public static void adjustHeap(int A[], int i, int length) {
int temp;
temp = A[i];//先取出当前元素的值,保存在临时变量中
//2*i+1为左子树i的左子树(因为i是从0开始的),2*k+1为k的左子树
for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
if (k + 1 < length && A[k] < A[k + 1]) {
//A[k]表示左孩子 A[k+1]表示右孩子
//左子结点的值<右子结点的值
k++;
//k指向右子结点
//当指针移动到了右孩子,因为是将最大的孩子结点与双亲交换,将大的编号用k表示
}
if (A[k] > temp) {//如果子结点>父结点
A[i] = A[k];//把较大的结点的值 赋值给当前结点
i = k;//i指向k 继续循环比较 因为k结点的下面可能还有子树
} else {
break;
}
}
//当for循环结束时,已经将以i为父结点的树的最大值放到了最顶上(局部的)
A[i] = temp;//将temp的值放到调整的位置
}
/**
* 初始化堆
*
* @param A
* @param length
*/
public static void buildMaxHeap(int[] A, int length) {
for (int i = length / 2 - 1; i >= 0; i--) {
adjustHeap(A, i, length);
}
}
/**
* 堆排序具体流程
*
* @param A
*/
public static void heapSort(int A[]) {
int t;
//先建立大根堆
buildMaxHeap(A, A.length);
for (int j = A.length - 1; j > 0; j--) {
//交换
t = A[j];
A[j] = A[0];
A[0] = t;
//调整堆
adjustHeap(A, 0, j);
}
}
}