什么是堆?
堆数据结构是一个数组对象,可以很容易地将其可视化为完整的二叉树。有两种类型的堆。第一个是最大堆,第二个是最小堆。最大堆是二进制树的一种特殊类型。最大堆的根大于其子根。另一个堆是“最小堆”,这也是一种特殊类型的堆,其根值比其子项的值低。我们可以使用堆排序算法对数组值进行排序。在此算法中,将使用生成的堆来重建堆。堆排序的复杂度为O(n.log(n))。堆排序最慢,但对于大型数据集来说是更好的选择。堆的所有节点还满足以下关系:每个节点上的键值至少与其子键值一样大。
无花果最大堆 | 无花果堆 |
堆排序的优点
- 堆排序算法表现出一致的性能。与最差情况下的性能,最佳情况下的性能,平均情况下的性能复杂度相同,O(n log n)
- 堆排序算法非常有效。这对于排序大量元素非常有效。这意味着没有其他排序算法可以在比较中表现更好。
- 内存使用量最少。相反,合并排序算法需要更多的存储空间。同样,Quicksort算法由于具有递归特性,因此需要更多的堆栈空间。
- 堆排序算法比其他同等有效的排序算法更易于理解,因为它不使用递归。
堆排序的局限性
- 这不是一个稳定的排序。
- 它需要更多的处理时间。
堆排序算法
- 以二叉树形式排列节点。
- 节点应按照特定规则进行排列。
- 用户在指定的限制内输入堆的大小。该程序使用节点具有随机生成的键值的方式生成相应的二叉树。
- 生成堆操作:设“ n”为树中的节点数,“ i”为树的键。为此,程序使用称为“堆”的操作。调用Heapify时,“ i”的左右子树都是堆。Heapify的功能是通过与较大的子项交换自身,使“ i”安定下来。
- 删除最大元素:程序通过与最后一个元素交换来删除根堆中最大的元素。
- 该程序执行Heapify(新的根),以便生成的树满足heap属性。
- 重复步骤3到步骤6,直到堆为空。
示例1
此示例显示堆排序的工作方式。
考虑使用堆进行排序的数字76、21、20、95、16、19、45、45、23。
- 首先,我们从列表中选取第一个元素76。将其作为根节点。
- 接下来,从列表中选择第二个元素21。将其插入到根节点76的左侧。
- 然后,从列表中取出第三个元素20进行插入。将其插入到根节点的右侧。
- 取第四个元素95。将其插入左侧节点21。插入的元素大于父元素,因此将95与21交换。但是父节点76小于子节点95,因此交换了95和76。 。交换后95成为根节点。
- 考虑下一个要插入树中的元素16。将其插入左侧。存在左节点,因此将其插入到76的右侧。
- 元素19插入到95的右侧,因为左侧变满了。将元素19插入节点20的左侧。
- 现在,元素45将插入到20的右侧。但是,父元素的值小于子元素的值,因此将45换为20。
- 现在,右侧已完全填充,因此在左侧添加下一个元素45。元素45插入左侧的最后一个节点,即21。但是,父元素的值小于子元素的值,因此将45与21交换。
- 将最后一个元素23插入到左侧节点45中。45的左侧已经填充,因此将元素23插入45的右侧。
- 最后,我们得到了排序的堆树。
用于堆排序的Java示例程序
public class HeapSortEx {
public static void main(String a[]) {
int i;
// Numbers which are to be sorted
int n[] = { 76, 21, 20, 95, 16, 19, 45, 45, 23 };
// Displays the numbers before sorting
System.out.print("Before sorting, numbers are ");
for (i = 0; i < n.length; i++) {
System.out.print(n[i] + " ");
}
System.out.println();
// Sorting in ascending order using Heap Sort
for (i = n.length; i > 1; i--) {
initializeheapSort(n, i - 1);
}
// Displaying the numbers after sorting
System.out.print("After sorting, numbers are ");
for (i = 0; i < n.length; i++) {
System.out.print(n[i] + " ");
}
}
public static void initializeheapSort(int n[], int n_ubound) {
int i, o;
int lChild, rChild, mChild, root, temp;
root = (n_ubound - 1) / 2;
for (o = root; o >= 0; o--) {
for (i = root; i >= 0; i--) {
lChild = (2 * i) + 1;
rChild = (2 * i) + 2;
if ((lChild <= n_ubound) && (rChild <= n_ubound)) {
if (n[rChild] >= n[lChild])
mChild = rChild;
else
mChild = lChild;
} else {
if (rChild > n_ubound)
mChild = lChild;
else
mChild = rChild;
}
if (n[i] < n[mChild]) {
temp = n[i];
n[i] = n[mChild];
n[mChild] = temp;
}
}
}
temp = n[0];
n[0] = n[n_ubound];
n[n_ubound] = temp;
return;
}
}
输出