堆排序解析
2016-02-01 10:39
309 查看
首先要了解堆的性质,我这里简答总结一下(这里说的是小堆):
1、堆是一棵完全二叉树
2、对于大堆中的任何一个非叶子节点,节点的值必须小于左右孩子节点值。
由此可知,对于小堆而言,根节点就是最小值了,那么我们每次拿走根节点,拿走的顺序就是递增序列的。
排序的元素在数组中,而堆也是一棵完全二叉树,所以直接用数组表示二叉树。
对于完全二叉树中的K节点,其满足一下性质:
1、K节点的父节点为( k - 1 ) / 2
2、K节点的左子节点为2K + 1
3、K节点的右子节点为2K + 2
所以堆排序的步骤如下:
1、填充二叉树元素,由于我们直接用源数据表示二叉树,所以这里不用写了。
2、由堆的性质可知,任何叶子节点都是满足堆的性质的,所以找到第一个非叶子节点的节点,从该节点开始,调整所有节点,让他们满足堆的性质
3、移走堆的根节点,得到当前的最大值。
4、将最后一个节点移至根节点,此时除了根节点外其余节点都是满足要求的,重新调整堆,重复第3步。
[cpp] view
plaincopy
void heapAdjust(int a[], int n, int index) //建立的是小根堆
{
int l = 2 * index + 1; //左子节点索引
int r = 2 * index + 2; //右子节点索引
if ( r >= n && l >= n ) return; //该节点没有子节点
int left = 0x7FFFFFFF, right = 0x7FFFFFFF;
if ( l < n ) left = a[l];
if ( r < n ) right = a[r];
if (a[index] <= left && a[index] <= right ) return; //节点值小于左右子节点值,符合条件,直接返回
if (left < right) //节点与较小的子节点交换
{
int t = a[index];
a[index] = left;
a[l] = t;
heapAdjust(a, n, l);
}
else
{
int t = a[index];
a[index] = right;
a[r] = t;
heapAdjust(a, n, r);
}
}
void heapSort(int a[], int n)
{
for ( int i = (n - 1) / 2; i >= 0; --i) //最后一个非叶子节点,也就是左后一个叶子节点的父节点
{
heapAdjust(a, n, i);
}
while (n > 0)
{
printf("%d ", a[0]);
int t = a[0]; //移走最小值
a[0] = a[n-1];
a[n-1] = t;
n--; //堆变小
heapAdjust(a, n, 0);
}
}
int main()
{
int a[] = {3, 5, 1, 4, 7, 3, 2, 5, 3, 8};
for ( int i = 0; i < 10; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
heapSort(a, 10);
printf("\nAfter sort:\n");
for ( int i = 0; i < 10; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
由于建立的是小根堆,所以最后得到是将序列。
最后附一个堆排的动画
1、堆是一棵完全二叉树
2、对于大堆中的任何一个非叶子节点,节点的值必须小于左右孩子节点值。
由此可知,对于小堆而言,根节点就是最小值了,那么我们每次拿走根节点,拿走的顺序就是递增序列的。
排序的元素在数组中,而堆也是一棵完全二叉树,所以直接用数组表示二叉树。
对于完全二叉树中的K节点,其满足一下性质:
1、K节点的父节点为( k - 1 ) / 2
2、K节点的左子节点为2K + 1
3、K节点的右子节点为2K + 2
所以堆排序的步骤如下:
1、填充二叉树元素,由于我们直接用源数据表示二叉树,所以这里不用写了。
2、由堆的性质可知,任何叶子节点都是满足堆的性质的,所以找到第一个非叶子节点的节点,从该节点开始,调整所有节点,让他们满足堆的性质
3、移走堆的根节点,得到当前的最大值。
4、将最后一个节点移至根节点,此时除了根节点外其余节点都是满足要求的,重新调整堆,重复第3步。
[cpp] view
plaincopy
void heapAdjust(int a[], int n, int index) //建立的是小根堆
{
int l = 2 * index + 1; //左子节点索引
int r = 2 * index + 2; //右子节点索引
if ( r >= n && l >= n ) return; //该节点没有子节点
int left = 0x7FFFFFFF, right = 0x7FFFFFFF;
if ( l < n ) left = a[l];
if ( r < n ) right = a[r];
if (a[index] <= left && a[index] <= right ) return; //节点值小于左右子节点值,符合条件,直接返回
if (left < right) //节点与较小的子节点交换
{
int t = a[index];
a[index] = left;
a[l] = t;
heapAdjust(a, n, l);
}
else
{
int t = a[index];
a[index] = right;
a[r] = t;
heapAdjust(a, n, r);
}
}
void heapSort(int a[], int n)
{
for ( int i = (n - 1) / 2; i >= 0; --i) //最后一个非叶子节点,也就是左后一个叶子节点的父节点
{
heapAdjust(a, n, i);
}
while (n > 0)
{
printf("%d ", a[0]);
int t = a[0]; //移走最小值
a[0] = a[n-1];
a[n-1] = t;
n--; //堆变小
heapAdjust(a, n, 0);
}
}
int main()
{
int a[] = {3, 5, 1, 4, 7, 3, 2, 5, 3, 8};
for ( int i = 0; i < 10; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
heapSort(a, 10);
printf("\nAfter sort:\n");
for ( int i = 0; i < 10; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
由于建立的是小根堆,所以最后得到是将序列。
最后附一个堆排的动画
相关文章推荐
- python 命令行参数
- jquery.validate使用攻略 第五步 正则验证
- 最短路算法(Floyd、Dijsktra、Bellman-Ford、SPFA)
- (三) shiro通过jdbc连接数据库
- Android中自定义属性Attr的详解使用.
- Linux共享内存使用常见陷阱与分析
- uva1363
- Spring Boot——2分钟构建spring web mvc REST风格HelloWorld
- 自动平滑轮播、左右循环view
- mac无法充电解决方法
- linux机制与策略
- nginx-rtmp-module
- ios移动端部分手机不支持background-attachment: fixed 的解决办法
- Oracle 基于Windows访问带端口的远程服务器
- nc 命令传文件
- edatagrid扩展,仿kettle形式的表格实现
- 安装spark ha集群
- const int a = 10; int *p = (int *)&a; *p = 100; a的值到底有没有改变
- 11.数据类型
- jquery validate使用攻略 第四步