堆与堆排序--递归与非递归java实现
2017-04-05 09:30
597 查看
堆排序是利用完全二叉树的结构思想,对线性数组进行排序的。
最大堆进行升序排序的基本思想:
① 初始化堆:将数列a[0...n-1]构造成最大堆。
② 交换数据:将a[0]和a[n-1]交换,使a[n-1]是a[0...n-1]中的最大值;然后将a[0...n-2]重新调整为最大堆。 接着,将a[0]和a[n-2]交换,使a[n-2]是a[0...n-2]中的最大值;然后将a[0...n-3]重新调整为最大值。 依次类推,直到整个数列都是有序的。
在第一个元素的索引为 0 的情形中:
性质一:索引为i的左孩子的索引是 (2*i+1);
性质二:索引为i的左孩子的索引是 (2*i+2);
性质三:索引为i的父结点的索引是 floor((i-1)/2);
堆分为大顶堆和小顶堆,
满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,
满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆
before sort:[4, 5, 2, 1, 8, 10, 2]
after sort:[1, 2, 2, 4, 5, 8, 10]
堆排序性能;
空间效率:常数辅助单元,空间复杂度为O(1)
时间效率:建堆时间是O(n),之后有n-1次向下调整堆,每次调整堆的时间复杂度为O(h),最好,最坏,平均复杂度是O(nlog)
稳定性:堆排序是一种选择排序,是不稳定的排序算法。
最大堆进行升序排序的基本思想:
① 初始化堆:将数列a[0...n-1]构造成最大堆。
② 交换数据:将a[0]和a[n-1]交换,使a[n-1]是a[0...n-1]中的最大值;然后将a[0...n-2]重新调整为最大堆。 接着,将a[0]和a[n-2]交换,使a[n-2]是a[0...n-2]中的最大值;然后将a[0...n-3]重新调整为最大值。 依次类推,直到整个数列都是有序的。
在第一个元素的索引为 0 的情形中:
性质一:索引为i的左孩子的索引是 (2*i+1);
性质二:索引为i的左孩子的索引是 (2*i+2);
性质三:索引为i的父结点的索引是 floor((i-1)/2);
堆分为大顶堆和小顶堆,
满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,
满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆
import java.util.Arrays; /** * 堆与堆排序 * @author mine_song 2017.04.05 */ public class HeapSort { public static void main(String[] args) { int arr[] = { 4, 5, 2, 1, 8, 10, 2 }; System.out.println("before sort:" + Arrays.toString(arr)); heapSortAsc(arr, arr.length); System.out.println("after sort:" + Arrays.toString(arr)); } /** * 数组从0作为第一个结点,从下往上,从右往左, 第一个非叶结点为len / 2 - 1下标位置 * * @param arr * 需要建立大顶堆的数组 * @param len * 数组的长度 */ public static void buildMaxHeap(int arr[], int len) { // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个大顶堆。 for (int i = len / 2 - 1; i >= 0; i--) // adjustDown(arr, i, len) adjustHeapWithRecur(arr, i, len); } /** * 大顶堆的向下调整算法 (非递归实现) * 注:数组实现的堆中, 第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。 * 其中,N为数组下标索引值,如数组中第1个数对应的N为0。 * * @param arr * 待排序的数组 * @param start * 被下调节点的起始位置(一般为0,表示从跟元素开始) * @param end * 截至范围(一般为数组中最后一个元素的索引) */ public static void adjustDown(int[] arr, int start, int end) { int cur = start;// 当前(current)节点的位置 int temp = arr[cur]; int left = 2 * start + 1;// left左孩子,left + 1右孩子 for (; left <= end; cur = left, left = 2 * left + 1) { // 选择左右孩子较大者 if (left < end && arr[left] < arr[left + 1]) left++; // 当前结点和左右孩子大小相比较 if (temp >= arr[left]) break; // 当前结点比左右孩子的较大者小 else { // 交换 arr[cur] = arr[left]; arr[left] = temp; } } } /** * 大顶堆的向下调整算法 (递归实现) * * @param arr * @param start * @param end */ public static void adjustHeapWithRecur(int[] arr, int start, int end) { int temp = arr[start]; int left = 2 * start + 1; if (left >= end) return; if (left < end - 1 && arr[left] < arr[left + 1]) left++; if (temp >= arr[left]) return; else { arr[start] = arr[left]; arr[left] = temp; } // 继续调整被破坏的子堆 adjustHeapWithRecur(arr, left, end); } /** * 升序排序 * * @param arr * 排序数组 * @param len * 数组长度 */ public static void heapSortAsc(int arr[], int len) { buildMaxHeap(arr, len); // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素 for (int i = len - 1; i > 0; i--) { // 把最大值放在数组的末尾 swap(arr, i, 0); // 继续调整0~i-1使之成为最大堆 adjustDown(arr, 0, i - 1); } } // 交换 private static void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; } }运行结果:
before sort:[4, 5, 2, 1, 8, 10, 2]
after sort:[1, 2, 2, 4, 5, 8, 10]
堆排序性能;
空间效率:常数辅助单元,空间复杂度为O(1)
时间效率:建堆时间是O(n),之后有n-1次向下调整堆,每次调整堆的时间复杂度为O(h),最好,最坏,平均复杂度是O(nlog)
稳定性:堆排序是一种选择排序,是不稳定的排序算法。
相关文章推荐
- 归并排序的递归与非递归实现java
- 递归与非递归实现树的遍历(java)
- Java 递归与非递归实现快速排序
- java扫描文件夹下面的所有文件(递归与非递归实现)
- 二分查找的递归与非递归实现【Java版】
- 归并排序的递归与非递归实现Java
- java递归与非递归实现扫描文件夹下所有文件
- 笔试面试算法经典--二叉树的镜像-递归与非递归实现(Java)
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
- 归并排序的递归与非递归实现理解(Java)
- [java] 二叉树的后序遍历(递归与非递归实现)
- 二叉树遍历的递归与非递归实现(java)
- JAVA 递归与非递归斐波那契数列的实现
- JAVA递归与非递归实现斐波那契数列
- 二分查找算法java版实现(递归实现与非递归实现)
- 快速排序 的原理及其java实现(递归与非递归)
- 递归与非递归方式判断二叉树是否对称&& 按行打印二叉树【java实现】
- 算法(第四版)学习笔记之二分查找的递归与非递归java实现
- java递归实现堆排序
- 图的深度优先遍历算法的递归与非递归JAVA实现