八、堆排序(平均时间复杂度:O(nlogn))
1、介绍:
1)堆排序是利用堆这种数据结构而设计的一种排序算法,属于选择排序的一 种,是不稳定的排序。
2)堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子 结点的值(没有要求其左右孩子的大小关系),称为大顶堆(常用来升序)。
3)每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆(用来降序)。
2、思想:
1)将待排序序列构造成一个大顶堆(以数组形式存放)。
2)此时,整个序列的最大数就是堆顶的根节点。
3)将其与末尾元素进行交换,此时末尾就是最大值。
4)然后将剩余的n-1个元素重新构造成一个堆,这样就会得到n个元素的次小值, 再反复执行,得到一个有序序列。
5)可以看到在构建大顶堆的过程中,元素的个数逐渐减少,最后就得到一个有序 序列。
3、思路图解:
1)将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆
2)将堆顶元素与末尾元素交换,将最大元素沉到数组末端
3)重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反 复执行调整交换步骤,直到整个序列有序。
4、代码如下:
//堆排序的方法
public static void heapSort(int[] arr){
int temp = 0;
//将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆
for(int i = arr.length / 2 - 1; i >= 0; i--){
adjustHeap(arr,i,arr.length);
}
/*
将堆顶元素与末尾元素交换,将最大元素沉到数组末端
重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整交换步骤,直到整个序列有序。
*/
for(int j = arr.length - 1; j > 0; j--){
//交换
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjustHeap(arr,0,j);//每次的第一个非叶子节点开始调整
}
}
//将一个二叉树(以数组的形式),调整成大顶堆
/**
*完成将以i对应的非叶子结点的局部树调整成大顶堆
*举例 int arr[] = {4,6,8,5,9}; =>i = 1 =>经过该方法处理=>得到{4,9,8,5,6},会进行局部处理
* @param arr 调整的数组
* @param i 表示非叶子节点在数组中的索引
* @param length 表示对多少个元素继续调整,length是在逐渐的减小
*/
public static void adjustHeap(int[] arr,int i,int length){
int temp = arr[i];//先取出当前元素的值,保存在临时变量
//开始调整
//k = i * 2 + 1指的是k是i的结点的左子结点
for (int k = i * 2 + 1; k < length; k = k * 2 + 1){
if(arr[k] < arr[k+1] && (k + 1) < length){//说明左子结点的值小于右子结点的值
k++;//k指向右子节点
}
if(arr[k] > temp){//如果子结点大于父结点
arr[i] = arr[k];//把子结点的值赋给父结点
i = k;//记录下子结点的下标
}else {
break;//因为调整是自下向上,自左向右的,可以直接退出循环
}
}
//循环结束完,我们已经将以i为父结点的树的最大值,放在了最顶上(局部)
arr[i] = temp;//将temp值放到调整后的位置
}
九、小结:
1、总共有8个排序算法:直接插入排序和希尔排序属于插入排序、简单选择排序和堆排序属于选择排序、冒泡排序和快速排序属于交换排序、归并排序、基数排序。
2、排序算法比较: