本文内容来源于《漫画算法》和数据结构教材
这里提到的堆是一个二叉堆,本质上是一颗完全二叉树。堆排序只需要一个记录大小的辅助空间。
1.java实现
void downAdjust(int[] arr, int parentIndex, int length) {
int temp = arr[parentIndex];
int childIndex = 2 * parentIndex + 1;
while (childIndex < length) {
if (childIndex + 1 < length && arr[childIndex + 1] > arr[childIndex]) {
childIndex++;
}
if (temp >= arr[childIndex])
break;
arr[parentIndex] = arr[childIndex];
parentIndex = childIndex;
childIndex = 2 * childIndex + 1;
}
arr[parentIndex] = temp;
}
void heapSort(int[] arr) {
for (int i = (arr.length - 2) / 2; i >= 0; i--) {
downAdjust(arr, i, arr.length);
}
System.out.println(Arrays.toString(arr));
for (int i = arr.length - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
downAdjust(arr, 0, i);
}
}
@Test
public void fun1() {
int[] arr = new int[] { 1, 3, 2, 6, 5, 7, 8, 9, 10, 0 };
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
2.C语言实现
#include<iostream>
using namespace std;
void HeapAdjust(int arr[], int s, int m) {
int temp = arr[s];
for (int j = 2 * s + 1; j <= m; j = 2 * j + 1) {
if (j < m && arr[j] < arr[j + 1])
++j;
if (temp > arr[j]) {
break;
}
arr[s] = arr[j];
arr[j] = temp;
s = j;
}
arr[s] = temp;
}
void HeapSort(int arr[]) {
int len = 8;
for (int i = len / 2 - 1; i >= 0; --i) {
HeapAdjust(arr, i, len - 1);
}
cout << "-------------------------" << endl;
for (int i = len - 1; i > 0; --i) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
HeapAdjust(arr, 0, i - 1);
}
}
int main(int argc, char* argv[]) {
int arr[] = { 49, 38, 65, 97, 76, 13, 27, 49 };
HeapSort(arr);
int len = 8;
for (int i = 0; i < len; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
堆排序的练习java版[漫画算法]
堆本质上是一颗完全二叉树,用数组存储,
parent,leftChild,rightChild
他们之间的数组下标的关系如下:
{
l
e
f
t
C
h
i
l
d
=
2
∗
p
a
r
e
n
t
+
1
;
r
i
g
h
t
C
h
i
l
d
=
2
∗
p
a
r
e
n
t
+
2
;
\begin{cases}leftChild=2*parent+1;\\ rightChild=2*parent+2;\end{cases}
{leftChild=2∗parent+1;rightChild=2∗parent+2;
堆排序算法步骤
1.把无序数组构建成二叉堆。
2.循环删除堆顶元素,并将该元素移到集合尾部,调整堆产生新的堆顶。
(这里的删除并非真的删除只是移动到了数组的后面相应的位置上)
时间复杂度O(nlogn)
空间复杂度O(1)
从宏观上看堆排序和快速排序的异同
相同点,1.堆排序和快速排序的平均时间复杂度都是O(nlogn),并且都是不稳定排序。
不同点,1.快速排序的最坏时间复杂度是O(n^2);而堆排序的最坏时间复杂度稳定在O(nlogn)
2.此外快排的递归和非递归方式的空间复杂度都是O(logn),
而堆排序的空间复杂度是O(1)
在漫画算法里面,有许多的堆调整的示意图,非常有助于理解。
堆的定义如下:n个元素的序列
{
k
1
,
k
2
,
.
.
.
,
k
n
,
}
\lbrace k_{1},k_{2},...,k_{n}, \rbrace
{k1,k2,...,kn,}当且仅当满足如下关系时,称之为堆。这里教材定义的下标是从1开始的,实际程序的下标是从0开始的,注意转换
{
k
i
⩽
k
2
i
k
i
⩽
k
2
i
+
1
\begin{cases} k_{i} \leqslant k_{2i}\\ k_{i} \leqslant k_{2i+1} \end{cases}
{ki⩽k2iki⩽k2i+1或
{
k
i
⩾
k
2
i
k
i
⩾
k
2
i
+
1
\begin{cases} k_{i} \geqslant k_{2i}\\ k_{i} \geqslant k_{2i+1} \end{cases}
{ki⩾k2iki⩾k2i+1
(
i
=
1
,
2
,
.
.
.
,
⌊
n
2
⌋
)
(i=1,2,...,\lfloor \frac{n}{2} \rfloor)
(i=1,2,...,⌊2n⌋)
若将和此序列对应的一维数组(即以一维数组做此序列的存储结构)看成是一个完全二叉树,则堆的含义表名,完全二叉树中所有非终端节点的值均不大于(或不小于)其左右孩子节点的值。由此,若序列
{
k
1
,
k
2
,
.
.
.
,
k
n
,
}
\lbrace k_{1},k_{2},...,k_{n}, \rbrace
{k1,k2,...,kn,}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
漫画算法里面的定义还是比较浅显易懂的。教材定义太复杂和吓人。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)