堆排序-博客园
2009-11-10 09:17
218 查看
先给出大根堆的定义:完全二叉树,任一非叶子结点都大于等于它的孩子,也就是说根结点是最大的。而且显然大根堆的任一棵子树也是大根堆。
堆排序的基本思想是:记录区的分为无序区和有序区前后两部分;用无序区的数建大根堆,得到的根(最大的数)和无序区的最后一个数交换,也就是将该根归入有序区的最前端;如此重复下去,直至有序区扩展至整个记录区。
具体操作可按下面步骤实现:
1。建大根堆
2。交换根和无序区最后一个数
3。重建大根堆,因为交换只是使根改变了,所以左右子树依然分别是大根堆。
4。比较根,左子树的根和右子树的根,如果根最大,则无须再作调整,树已经是大根堆了;如果左子树的根最大,交换它与根,再递归调整左子树;如果右子树的根最大,交换它与根,再递归调整右子数。
5。递归调整到叶子的时候,树就是大根堆了。
现在还要解决的就是如何建那个初始的大根堆了,把整个数组R0,R1,...,R(n-1)看成一个完全二叉树,只要从后往前依次将以该结点为根的子树调整为大根堆就行了。而实际上,序号大于[n/2]的结点都是叶子结点,可看作是大根堆,所以只需调整[n/2],[n/2]-1,...,1的结点作为根节点的子树就可以了。
public static void HEAPSORT(int[] R)
{
//建初始大根堆
for (int i = R.Length / 2+Convert.ToInt32(Math.IEEERemainder(R.Length,2)); i >0 ; i--)
{
SIFT(R, i-1, R.Length-1);
}
//循环进行交换并重建大根堆
for (int j = R.Length - 1; j > 0; j--)
{
//交换根和无序区最后一个数
int t = R[0]; R[0] = R[j]; R[j] = t;
SIFT(R, 0, j-1);
}
}
public static void SIFT(int[] R,int iFrom,int iTo)
{
int i = iFrom; //根结点下标
int j = 2 * iFrom + 1; //左孩子下标
int temp = R[i]; //要调整的根结点,假定左右子树已为大根堆
while (j <= iTo)
{
if ((j < iTo) && ((R[j] < R[j + 1])))
{
j++;//如果右孩子大于左孩子,将j指向右孩子,以便接下来统一处理
}
if ((R[j] > temp))
{
//比根结点大的孩子上移
R[i] = R[j];
//指向下一个子树
i = j;
j = 2 * i + 1;
}
else
{
break;
}
}
//定位要当初的根结点到正确的位置
R[i] = temp;
}
0
0
0
(请您对文章做出评价)
堆排序的基本思想是:记录区的分为无序区和有序区前后两部分;用无序区的数建大根堆,得到的根(最大的数)和无序区的最后一个数交换,也就是将该根归入有序区的最前端;如此重复下去,直至有序区扩展至整个记录区。
具体操作可按下面步骤实现:
1。建大根堆
2。交换根和无序区最后一个数
3。重建大根堆,因为交换只是使根改变了,所以左右子树依然分别是大根堆。
4。比较根,左子树的根和右子树的根,如果根最大,则无须再作调整,树已经是大根堆了;如果左子树的根最大,交换它与根,再递归调整左子树;如果右子树的根最大,交换它与根,再递归调整右子数。
5。递归调整到叶子的时候,树就是大根堆了。
现在还要解决的就是如何建那个初始的大根堆了,把整个数组R0,R1,...,R(n-1)看成一个完全二叉树,只要从后往前依次将以该结点为根的子树调整为大根堆就行了。而实际上,序号大于[n/2]的结点都是叶子结点,可看作是大根堆,所以只需调整[n/2],[n/2]-1,...,1的结点作为根节点的子树就可以了。
public static void HEAPSORT(int[] R)
{
//建初始大根堆
for (int i = R.Length / 2+Convert.ToInt32(Math.IEEERemainder(R.Length,2)); i >0 ; i--)
{
SIFT(R, i-1, R.Length-1);
}
//循环进行交换并重建大根堆
for (int j = R.Length - 1; j > 0; j--)
{
//交换根和无序区最后一个数
int t = R[0]; R[0] = R[j]; R[j] = t;
SIFT(R, 0, j-1);
}
}
public static void SIFT(int[] R,int iFrom,int iTo)
{
int i = iFrom; //根结点下标
int j = 2 * iFrom + 1; //左孩子下标
int temp = R[i]; //要调整的根结点,假定左右子树已为大根堆
while (j <= iTo)
{
if ((j < iTo) && ((R[j] < R[j + 1])))
{
j++;//如果右孩子大于左孩子,将j指向右孩子,以便接下来统一处理
}
if ((R[j] > temp))
{
//比根结点大的孩子上移
R[i] = R[j];
//指向下一个子树
i = j;
j = 2 * i + 1;
}
else
{
break;
}
}
//定位要当初的根结点到正确的位置
R[i] = temp;
}
0
0
0
(请您对文章做出评价)
相关文章推荐
- .NET设计模式系列文章 很有名的博客园TerryLee的系列文章,设计模式不可多得的好文
- 算法学习之排序学习之堆排序和如何建堆
- 纪念一下--开始住入博客园
- 如何防止博客园文章被窃取
- 在ASP.NET中支持断点续传下载大文件 - star163 - 博客园
- STL 堆排序
- 不知是不是年纪大了,常想起博客园,博客堂的旧事.博客堂好像不再存在了,博客园经营的越红火了.还记得这些人,早期的大牛人?
- JSON.stringify 语法讲解 - 随风浪迹天涯 - 博客园
- 博客园的“随笔、文章、新闻、日记”有啥区别
- 排序算法(三):堆排序
- 【算法学习】堆排序(Heap Sorting)
- 快速排序和堆排序
- 数据结构&算法实践—【排序|选择排序】堆排序
- 算法 排序 python 实现--堆排序
- 堆排序
- 堆与堆排序
- 快速排序、堆排序、希尔排序实现
- 今天开通了博客园的博客啦
- 博客园的搬家功能真是弱爆了
- 堆排序