堆排序

来源:互联网 发布:证券时报股市大数据 编辑:程序博客网 时间:2024/05/19 17:26

堆排序思想

----雨竹清风

堆排序是一种树形选择排序方法,它是将待排序列看做成一棵完全二叉树,是利用完全二叉树中双亲与孩子结点之间的关系,来处理当前的无序序列中元素。

堆的定义:n个元素的无序序列{k1,k2,k3…kn};当前仅当满足下面关系时称为堆:

小顶堆:ki k2i  && ki k2i+1

大顶堆:ki k2i  && ki k2i+1

例如:大顶堆 和 小顶堆

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

大体思路:(以大顶堆为例)先将无序序列调整成大顶堆。堆排序过程中将最大值输出,即与最后一个元素交换,交换后就已经不是一个大顶堆,所以需要调整成大顶堆。

以无序序列{49,38,65,97,76,13,27,49}为例,对其进行堆排序。

1.调整成大顶堆

我们首先将这个无序序列看成一棵完全二叉树,如下图所示:

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

 

然后将其调整成大顶堆,从第一个非叶子节点开始调整,第一个非叶子节点是第n/2个结点(元素),判断以它为根的子树是否是一个大顶堆,若不是大顶堆,则进行调整。直到所有的元素组成的是一棵大顶堆为止。过程如下图所示:

堆排序 - 雨竹清风 - 雨竹清风的博客

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

 

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

2.堆排序

将第一个元素和最后一个元素交换,然后调整剩余的元素,调整为大顶堆。

 堆排序 - 雨竹清风 - 雨竹清风的博客

 

3897交换,调整除97之外的元素,调整成大顶堆。调整后结果为:

堆排序 - 雨竹清风 - 雨竹清风的博客

 

7627交换,然后调整,结果如下:


堆排序 - 雨竹清风 - 雨竹清风的博客

 

然后交换6513,调整为:

堆排序 - 雨竹清风 - 雨竹清风的博客

 

交换1349,调整后的结果:

堆排序 - 雨竹清风 - 雨竹清风的博客

 

交换1349,调整后的结果:

堆排序 - 雨竹清风 - 雨竹清风的博客

 

 

交换3827,调整后的结果:

堆排序 - 雨竹清风 - 雨竹清风的博客

 

交换2713,调整后的结果:

 

堆排序 - 雨竹清风 - 雨竹清风的博客

 

最终的结果为:13 27 38 49 49 6576 97

/////////////堆排序的代码/////////////

堆排序主要由4个函数组成:

void BulidHeap(int A[], intlen);//建初始堆,A是一个数组,len是数组的长度

void AdjustDown(int A[],intk,int len);//开始调整,k是从哪个地方开始调整

void Swap(int A[],int i,intj);//将第i个位置的元素和第1个元素进行交换

void HeapSortPro(int A[], intlen);//堆排序

///////

HeapSortPro()是堆排序的大体步骤,首先创建一个大顶堆,第二步交换,调整。创建大顶堆调用BulidHeap()函数,交换调用Swap()函数,调整调用AdjustDown()函数。

BulidHeap()中调用的是AdjustDown()函数,对无序序列建立一个大顶堆。

   建立大顶堆时候,从最后一个非叶子结点开始调整。

在调整时候是最关键点:

   建立一个大顶堆,首先找到对应的左右孩子结点,判断哪个大,若右孩子大则将右孩子与该结点交换,否则左孩子与该结点交换。

直到调整到最后一个结点为止。

代码如下:

void AdjustDown1(int A[],intk,int len)//向下调整,开始调整,k是从哪个地方开始调整,

{

   int i = k * 2;

   for(i ; i < len ; i = i * 2)

   {

   //技巧

      if (A[i]< A[i + 1])//找到其左右孩子的最大的那个进行比较,若根比孩子最大的还大,就不用调整

      {

        ++i;

      }

//先判断不成立的情况,以便直接跳出循环,节省时间

      if (A[k] >A[i])//若大于则不用调整

     {

        break;

     }

      else

      {

        Swap(A, k, i);

        k = i;//为了继续向下调整

      }

   }

//i==len时候单独拿出来,节省了遍历for循环的时间

   if(i == len&& A[k] < A[i])

   {

      Swap(A, k, i);

   }

}

//////堆排序时间复杂度/////

堆排序方法对于记录数比较少的情况不值得提倡,但对于较大的文件还是比较有效。堆排序的时间复杂度为O(nlogn);

 

0 0
原创粉丝点击