总的来说,堆是一种高效的数据结构,它在实现优先队列、堆排序等场景中发挥着重要作用。
最大堆的定义是:对于堆中的任意节点 i,其值不小于其子节点的值。这意味着根节点是堆中的最大元素。
最大堆的一些基本操作包括:
最小堆的定义是:对于堆中的任意节点 i,其值不大于其子节点的值。这意味着根节点是堆中的最小元素。
最小堆的基本操作与最大堆类似,只是在插入和删除操作中的调整方式相反。
总体而言,堆是一种强大而灵活的数据结构,其在算法和软件工程中的应用广泛而深刻。通过充分理解堆的性质和操作,我们能够更好地解决各种问题,并设计出高效的算法。
堆排序是一种基于堆的排序算法,它利用了堆的特性来实现排序。该算法分为两个主要步骤:建堆和排序。
在建堆阶段,我们将无序数组构建成一个二叉堆。通常采用自底向上的方式,从最后一个非叶子节点开始,逐步向上调整,保持堆的性质。
让我们考虑一个简单的例子,假设我们有以下无序数组:
[ 4, 10, 3, 5, 1 ]
首先,将这个数组构建成一个最大堆。
[ 4, 10, 3, 5, 1]
[ 10,5, 3, 4, 1 ]
此时,我们已经完成了建堆的阶段,得到了一个最大堆。
在排序阶段,我们不断将堆的根节点与堆的最后一个元素交换,然后减小堆的大小,并通过向下调整(percolate-down)来保持堆的性质。
[ 1, 5, 3, 4, 10 ]
[ 5, 4, 3, 1, 10 ]
[ 4,5, 3, 1, 10]
[ 4, 1, 3, 5, 10 ]
最终,通过不断交换和调整,我们得到了有序的数组:
[ 1, 3, 4, 5, 10 ]
堆排序的时间复杂度为 (O(n log n)),其中 (n) 是数组的长度。虽然堆排序的常数因子较大,但它在实践中仍然是一个有效且稳定的排序算法。
4 10 10 10 3 ——》 4 3 ——》 5 3
5 1 5 1 4 1
//[ 4, 10, 3, 5, 1 ] n=5 i=1
public class HeapSort {
public void heapify(int arr[], int n, int i) {
int largest = i;
int leftChild = 2 * i + 1;
int rightChild = 2 * i + 2;
if (leftChild < n && arr[leftChild] > arr[largest]) {
largest = leftChild;
}
if (rightChild < n && arr[rightChild] > arr[largest]) {
largest = rightChild;
}
if (largest != i) {
int temp = arr[i];
arr[i] = arr[largest];
arr[largest] = temp;
heapify(arr, n, largest);
}
}
//[ 10,5, 3, 4, 1 ]
public void heapSort(int arr[]) {
int n = arr.length;
// Build max heap
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
// Heap sort
for (int i = n - 1; i > 0; i--) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
heapify(arr,i,0);
}
}
1,5,3,4,10 - 5,1,3,4,10 - 4,1,3,5,10 - 3,4,1,5,10 - 4,3,1,5,10 - 1,3,4,5,10
public static void main(String args[]){
int unsortedArray[] = {4,10,3,5,1};
HeapSort heapSort = new HeapSort();
heapSort.heapSort(unsortedArray);
System.out.print("Sorted array: ");
for(int i=0;i< unsortedArray.length; ++i){
System.out.println(unsortedArray[i]+" ");
}
}