堆排序的平均时间复杂度为 O(nlogn) ,空间复杂度为 Θ(1) 。
目录
堆排序HeapSort
算法流程
首先进行大顶堆的初始化,然后迭代地执行“把最大堆堆顶元素取出,与待排序数组末端元素交换;堆中元素个数减一,将剩余的堆继续调整为最大堆”的过程,直到堆中只剩一个元素,算法结束。
Cpp实现
//最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
void max_heapify(int* arr, int beg, int end){
int dad = beg, son = 2 * dad + 1;
while (son <= end){
if (son + 1 <= end && arr[son] < arr[son + 1]) ++son;
if (arr[dad] > arr[son]) return;
swap(arr[dad], arr[son]);
dad = son;
son = 2 * dad + 1;
}
}
void heap_sort(int* arr, int len){
if (!arr || len<2) return;
//大顶堆的初始化,从最后一个父节点开始调整
for (int i = len / 2 - 1; i >= 0; --i) max_heapify(arr, i, len-1);
for (int i = len-1; i > 0; --i){
swap(arr[0], arr[i]);//把最大堆堆顶元素取出,与待排序数组末端元素交换
max_heapify(arr, 0, i-1);//堆中元素个数减一,将剩余的堆继续调整为最大堆
}
}
reference:wiki
背景知识
二叉树
常被用于实现二叉查找树和二叉堆。
对任意树,
- 节点的度定义为该节点的分叉数(子女数)
- 树中节点数
=
总分叉数
+1
对任意二叉树,
- 子树有左右之分
- 第
i
层至多
2i−1 个节点 - 深度为
k
的树至多
2k−1 个节点 - 度为
0
的节点个数
= 度为 2 的节点个数+1
完全二叉树
除了最下一层外,其它各层的节点数目均已达最大值,且最下一层所有节点从左向右连续地紧密排列。
满二叉树
所有叶节点都在最底层的完全二叉树
平衡二叉树(AVL树)
当且仅当任何节点的两棵子树的高度差不大于1的二叉树
二叉搜索树(Binary Search Tree)
是指一棵空树或者具有下列性质的二叉树:
若节点x左子树不空,则左子树上所有节点的值均小于x的值;
若节点x右子树不空,则右子树上所有节点的值均大于x的值;
任意节点的左、右子树也分别为二叉查找树。
堆(Heap)
当且仅当n个元素满足下列关系时称之为堆:
k1,k2...ki...kn对小顶堆:(ki<=k2i,ki<=k2i+1);对大顶堆:(ki>=k2i,ki>=k2i+1)
即子结点的键值或索引总是小于(或大于)它的父节点。(其中,i = 1,2,3,4…n/2)
堆是一个近似完全二叉树的结构。
完全二叉树的一个“优秀”的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示(普通的一般的二叉树通常用链表作为基本容器表示),每一个结点对应数组中的一个元素。如下图所示:
img reference:blog
注意:数组都是 Zero-Based的。
对于给定的某个结点在数组中的下标 i,可以很容易的计算出该结点的父结点、孩子结点的下标:
-
i
的父节点下标
Parent(i)=floor((i−1)/2) -
i
的左孩子节点下标
Left(i)=2i+1 -
i
的右孩子节点下标
Right(i)=2i+2