堆排序

来源:互联网 发布:数据库分析工具 编辑:程序博客网 时间:2024/05/02 05:08

堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。

二叉堆的定义
:二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最大堆:

从图中可以看出

  1. 若父子结点下标为i,则左孩子的下标为i*2+1,右孩子的下标是i*2+2。
  2. 数组元素个数为size,则在下标size/2-1之后的结点都是叶子结点。
  3. 下标为size/2-1的结点是最后一个非叶子结点。
    ## 堆的插入删除 ##
    这是《数据结构C++语言描述》中最小堆的建立插入删除的图解。

    堆的插入
    由图可得,每次插入时都是从最后一个位置插,相当于将一个元素插入到有序的数组中去,则插入后一直向上调整直到0位置。
    代码如下
void HeapAdjustup(int a[],int i,int size)   //向上调整{    if(i > size)        return ;    int parent = (i-1)/2;    int min = parent;    if (parent <= size/2)   //不是叶子结点才调整    {        if(a[i] < a[min])            min = i;        if (min == parent)        {            swap(a[min],a[parent]);            HeapAdjustup(a,parent,size);        }    }}void MinHeapFixup(int a[],int i)  ///循环代码{    for(int j = (i-1)/2 ; (j >0 && i != 0) && (a[i] > a[j]);i = j,j = (i-1)/2)        swap(a[i],a[j]);}void InsertHeap(int a[],int size,int key){    a[size] = key;    HeapAdjustup(a,size,size+1);}

以下图为例分析小堆建立的过程,以及堆排序的原理

参考代码如下

void HeapAdjust(int a[],int i,int size)///向下调整{    if (i >= size)        return ;    int left = 2*i+1;  //左孩子的下标    int right = 2*i+2;//右孩子的下标    int min = i;  //设置最小的下标为i    if (i<=size/2) //不是叶子结点的才调整    {        if (left < size&&a[left] < a[min])     //找到它的左孩子右孩子以及自己中最小的那个            min = left;        if (right < size&&a[right] < a[min])            min = right;        if (min != i) //如果最小的不是自己,就交换        {            swap(a[i],a[min]);            HeapAdjust(a,min,size);   //递归调整以min为父节点的子树        }    }}void CreateHeap(int a[],int size){    for (int i = size/2-1;i>=0;--i)        HeapAdjust(a,i,size);}

删除的代码

void HeapAdjust(int a[],int i,int size)///向下调整{    if (i >= size)        return ;    int left = 2*i+1;  //左孩子的下标    int right = 2*i+2;//右孩子的下标    int min = i;  //设置最小的下标为i    if (i<=size/2) //不是叶子结点的才调整    {        if (left < size&&a[left] < a[min])     //找到它的左孩子右孩子以及自己中最小的那个            min = left;        if (right < size&&a[right] < a[min])            min = right;        if (min != i) //如果最小的不是自己,就交换        {            swap(a[i],a[min]);            HeapAdjust(a,min,size);   //递归调整以min为父节点的子树        }    }}void DeleteHeap(int a[],int size){    swap(a[0],a[size-1]);    HeapAdjust(a,0,size-1);}

至此,堆排序的原理以及实现代码已经写完。