排序_堆排

堆:Heap是计算机科学中一类特殊的数据结构的统称,通常是一个可以被看做一棵完全二叉树的数组对象。堆是非线性数据结构,相当于一给2一维数组,有两个直接后继。
堆的性质:堆中某个节点的值总是不大于或不小于其父节点的值,且总是一棵完全二叉树。
堆的分类:大根堆、小根堆
大根堆:将根节点最大的堆叫做最大堆或大根堆,及根节点的元素值最大,且所有父节点的值大于其左右子节点的值
小根堆:将根节点最小的堆叫做最小堆或小根堆,及根节点的元素值最小,且所有父节点的值小于其左右子节点的值
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆:(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)。若将和此次序列对应的一维数组看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)

以最大堆为例进行堆操作分析:
一:堆的上移动操作:如果修改堆中某个元素,使得它的值大于父节点的值,导致破坏了最大堆的性质,因此需要对该元素实现上移操作。上移一次后需要再次判断是否大于其父节点的值,直到上移至根节点为止
void sift_up(int *H,int i)
{
    while(i!=1)
    {
        if(H[i]>H[i/2])
            swap(H[i],H[i/2]);
        i=i/2;
    }
}

二:堆的下移操作:如果修改堆中某个元素,使得它的值小于其子节点值,导致破坏了最大堆的性质,,因此需要对该元素实现下移操作。 下移一次后需要再次判断是否小于其子节点的值,直到下移至叶节点为止
void sift_down(int *H,int m,int i)
{
    while((i=2*i)<=m)                         //判断该结点是否为叶子节点       
    {
        if(i+1<=m && H[i+1]>H[i])        //选取下移节点的左右子节点中较大的
            i++;
        if(H[i]>H[i/2])                            //i/2即为我们需要下移的元素,如果比子节点中最大元素小,进行交换
            swap(H[i],H[i/2]);
    }
}

三:堆的删除操作:如果我们删除下标为 i 的元素,可以用堆中最后1个元素替代i,然后对这个元素执行上移或者下移操作
void heap_delete(int *H,int i ,int &m)
{
    if(i>m)
        return;
    else
    {
        int a,b;
        a=H[i];
        b=H[m];
        H[i]=b;
        m--;
        if(a>b)
        {
            sift_down(H,m,i);
        }
        else
        {
            sift_up(H,i);
        }
    }
}

四:堆的插入操作:插入一个元素时,插入到堆最后1个元素后面,然后对该元素执行上移操作
void Insert(int *H,int &m,int num)
{
    m++;
    H[m]=num;
    sift_up(H,m);
}

五:堆的建立:以数组arr为对象建立堆数组hrr,g为arr数组元素个数,m为堆的元素个数该参数通过插入等操作带出,从Hrr[1]开始存储元素
void make_heap(int *arr,int *hrr,int g,int &m)
{
    m=0;
    for(int i=0;i     {
        Insert(hrr,m,arr[i]);
    }
}

六:堆的排序:假设堆有n个元素,由于堆的第一个元素一定是最大的元素,因此可以让第一个元素和第n个元素互换,然后对第一个元素执行下操作。接着,对n-1个元素执行相同的操作,让第一个元素与第n-1个元素互换,然后对第一个元素执行下移操作,依次类推,最后的堆就是从小到大排序好的堆。
void heap_sort(int *H,int m)
{
    int i;
    for(i=m;i>0;i--)
    {
        swap(H[i],H[1]);
        sift_down(H,i-1,1);
    }
}

以最大堆为例堆排序:
void HeapAdjust(int arr[], int pos, int len)//以堆的形式调整数组元素的位置
{
    int i = pos;
    int j = 2 * i + 1;
    int tmp = 0;
    for (j; j < len; j = 2 * i + 1)
    {
        if (j < len - 1 && arr[j + 1] > arr[j])++j;
        if (arr[i] >= arr[j])break;
        swap(arr[i],arr[j])
        i = j;
    }
}
void HeapSort(int arr[], int len)
{
    int tmp = 0;
    for (int i = len / 2 - 1; i >= 0; --i)
    {
        HeapAdjust(arr, i, len);
    }
    for (int i = len - 1; i > 0; --i)
    {
        swap(arr[0],arr[i]);
        HeapAdjust(arr, 0, i);
    }
}

你可能感兴趣的:(排序)