• 非递归方法的堆排序实现


    引言

    首先需要明确,如何根据父亲结点的位置得知孩子结点的位置,以及如何根据孩子结点的位置得知父亲结点的位置。

    假设数列索引从0开始,如果父亲结点的索引为i,那么左孩子索引为2i+1,右孩子索引为2i+2;如果孩子结点的索引为j,那么父亲结点的索引为(j-1)/2。

    堆排序的核心在于函数 void adjustdown(int *arr, int i, int end) ,其中第i+1个元素到最后一个元素均已满足堆结构,每次adjustdown可以使当前位置i的元素也满足堆结构。如果是大堆,则经过adjustdown后当前位置的元素最大;如果是小堆,则经过adjustdown后当前位置的元素最小。

    以下代码,将数列从小到大排序。采用大堆,并且使用了非递归的方法。函数adjustdown中的五个if语句实际上有一部分是可以合并的,但是为了逻辑清晰,在本代码中,完整保留下来了。注释我写的很用心,相信读者可以看懂。

    代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    
    static void show(int *arr, int len)
    {
        int index;
        for(index = 0; index < len; index++)
        {
            printf("%d ",arr[index]);
        }
        printf("
    ");
    }
    
    static void swap(int *left, int *right)
    {
        int tmp = *left;
        *left = *right;
        *right = tmp;
    }
    
    void adjustdown(int *arr, int i, int end)
    {
        int key = arr[i];
        int p = i;              
        int left = 2 * p + 1;
        /* 越界就是没孩子 */    /* 只要能进循环,一定有左孩子 */
        while( left <= end )
        {
            /* 有右孩子的情况下,大于等于左右孩子不用换 */
            if( (key >= arr[left]) && (left+1 <= end && key >= arr[left+1]))
            {
                break;
            }else if( key >= arr[left] && left + 1 > end) /* 没有右孩子,只有左孩子,且大于等于左孩子不用换*/
            {
                break;
            }else if(left + 1 <= end && arr[left+1] >= arr[left] && key < arr[left+1]) /* 与右孩子换。要保证有右孩子,且右孩子大于等于左孩子,父亲小于右孩子 */
            {
                swap(arr+p, arr+left+1);
                p = left + 1;         //父亲与谁换,就到谁的位置了
                 left = 2 * p + 1;      //父亲新的左孩子的位置
            }else if(left + 1 <= end && arr[left] > arr[left + 1] && key < arr[left])/* 与左孩子换。有右孩子的情况下,右孩子小于左孩子,父亲小于左孩子 */
            {
                swap(arr + p, arr + left);
                p = left;
                left = 2 * p + 1;
            }else if(left + 1 > end && arr[left] > key) /* 与左孩子换。没右孩子的情况下,只需父亲小于左孩子 */
            {
                swap(arr + p, arr + left);
                p = left;
                left = 2 * p + 1;
            }
        }    
    }
    
    
    void heap_sort(int *arr, int len)
    {
        int p;   // 最后一个父亲
        int end; // 最后一个有效下标
        /* 建一个大顶堆,从最后一个父亲开始调 */
        for(p = (len -1 -1) /2 ; p >= 0; p--)
        {
            adjustdown(arr, p ,len - 1);
        }
        /* 根结点的值最大,与末尾交换,并继续建立堆结构,再交换... */
        for(end = len - 1; end >= 1; end--)
        {
            swap(arr, arr + end );   // end已经是最大值
            adjustdown(arr,0,end-1);  // 从arr+1 到 end-1位置都是满足堆结构的
        }
    }
    
    int main(int argc, char *argv[])
    {
        int index;
        int arr[10];
        memset(arr,0,10);
        srand(time(NULL));
        for(index = 0; index < 10; index++)
        {
            arr[index] = rand()%20+1;
        }
        show(arr,10);
        
        heap_sort(arr,10);
        show(arr,10);
    
        system("pause");
        return 0;
    }
     
  • 相关阅读:
    套题 8.22
    套题 8.21
    P1042 乒乓球
    套题8.20
    #52. 【UR #4】元旦激光炮 (交互式题)
    #82. 【UR #7】水题生成器
    度度熊与邪恶大魔王
    wpf 获取image控件的图片并保存
    wpf 让正执行的程序暂停几秒钟
    wpf问题集锦
  • 原文地址:https://www.cnblogs.com/jianxinzhou/p/3954069.html
Copyright © 2020-2023  润新知