堆排序使用了“堆”数据结构来进行信息管理,因此,首先需要介绍一个数据结构“堆”。
堆
堆也叫二叉堆,是一个数组,可以被看作一个近似的完全二叉树,树上的每一个节点对应数组中的一个元素。除了最底层外,该树实2完全充满的,而且是从左向右填充。表示堆的对象A应有两个属性,A.data为数组,数组用于存储堆的数据,A.heapSize表示A.data[0,A.heapSize-1]中存放的是堆的有效元素。A.data的第一个元素为树的根节点。若下标从1开始,可以知道给定一个节点的下标i,该节点的父节点下标为i/2,该节点的左孩子下标为2i,右孩子下标为2i+1。但是往往在编写代码实现时,数组下标从0开始,此时,节点i的父节点下标为(i-1)/2,左孩子下标为2xi+1,右孩子下标为2x(i+1)。
下图分别为一个堆的二叉树和数组展现形式。
二叉堆可以分为最大堆和最小堆。最大堆满足A.data[parent[i]] ≥ A.data[i],最小堆满足A.data[parent[i]] ≤ A.data[i]。
堆排序
基于堆实现排序,可通过以下方法实现:
- MAX-HEAPIFY:此过程维护最大堆的性质,保证堆是一颗最大堆,时间复杂度为O(lgn);
- BUILD-MAX-HEAP:此过程从无序数组中构建一个最大堆,具有线性时间复杂度;
- HEAPSORT:对一个数组进行原址排序,时间复杂度为O(nlgn)。
java实现
定义堆的数据结构
/** * 堆结构 */ public class Heap { /** * 堆的大小 */ private int heapSize; /** * 存储堆的数组 */ private int[] heapDate; public int getHeapSize() { return heapSize; } public void setHeapSize(int heapSize) { this.heapSize = heapSize; } public int[] getHeapDate() { return heapDate; } public void setHeapDate(int[] heapDate) { this.heapDate = heapDate; } }
实现MAX-HEAPIFY方法
/** * 维护最大堆性质,时间复杂度为O(lgn) * * @param heap 最大堆 * @param i 维护堆的起始索引,从1开始 */ private void maxHeapIfy(Heap heap, int i) { // 左孩子下标 int left = 2 * i + 1; // 右孩子下标 int right = 2 * (i + 1); int largest; int[] heapNums = heap.getHeapDate(); // 每棵子树的孩子节点小于等于其父节点 if (left <= heap.getHeapSize() - 1 && heapNums[left] > heapNums[i]) { largest = left; } else { largest = i; } if (right < heap.getHeapSize() - 1 && heapNums[right] > heapNums[largest]) { largest = right; } if (largest != i) { int temp = heapNums[i]; heapNums[i] = heapNums[largest]; heapNums[largest] = temp; maxHeapIfy(heap, largest); } }
实现BUILD-MAX-HEAP方法
/** * 建堆 * * @param nums 用来构建堆的数组 * @return 建好的堆 */ private Heap buildHeap(int[] nums) { Heap heap = new Heap(); heap.setHeapSize(nums.length); heap.setHeapDate(nums); for (int i = nums.length / 2; i >= 0; i--) { maxHeapIfy(heap, i); } return heap; }
实现HEAPSORT方法
/** * 堆排序 * * @param nums 待排序的数组 */ public void heapSort(int[] nums) { // 建堆 Heap heap = buildHeap(nums); int[] heapDate = heap.getHeapDate(); // 从数组的最后一个元素开始,每次将堆的根节点与最后一个元素互换 for (int i = heapDate.length - 1; i >= 0; i--) { int temp = nums[0]; nums[0] = nums[i]; nums[i] = temp; // 将堆的大小减一,再次进行调整,使其满足堆的性质 heap.setHeapSize(heap.getHeapSize() - 1); maxHeapIfy(heap, 0); } }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。