算法 — 堆排序

本文内容和图片转载https://www.jianshu.com/p/0d383d294a80

堆(二叉堆)可以视为一棵完全的二叉树,完全二叉树的一个“优秀”的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示(普通的一般的二叉树通常用链表作为基本容器表示),每一个结点对应数组中的一个元素。

二叉堆一般分为两种:最大堆和最小堆。

最大堆:

最大堆示意图.png

最大堆中的最大元素值出现在根结点(堆顶)
堆中每个父节点的元素值都大于等于其孩子结点(如果存在)

最小堆:

最小堆示意图

最小堆中的最小元素值出现在根结点(堆顶)
堆中每个父节点的元素值都小于等于其孩子结点(如果存在)

堆排序

是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  • 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;

  • 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

堆排序的平均时间复杂度为 Ο(nlogn)。

算法步骤

1、创建一个堆 H[0……n-1];

2、把堆首(最大值)和堆尾互换;

3、把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;

4、重复步骤 2,直到堆的尺寸为 1。


堆排序.gif

排序动画过程解释

1、首先,将所有的数字存储在堆中
2、按大顶堆构建堆,其中大顶堆的一个特性是数据将被从大到小取出,将取出的数字按照相反的顺序进行排列,数字就完成了排序
3、在这里数字 5 先入堆
4、数字 2 入堆
5、数字 7 入堆, 7 此时是最后一个节点,与最后一个非叶子节点(也就是数字 5 )进行比较,由于 7 大于 5 ,所以 7 和 5 交互
6、按照上述的操作将所有数字入堆,然后从左到右,从上到下进行调整,构造出大顶堆
7、入堆完成之后,将堆顶元素取出,将末尾元素置于堆顶,重新调整结构,使其满足堆定义
8、堆顶元素数字 7 取出,末尾元素数字 4 置于堆顶,为了维护好大顶堆的定义,最后一个非叶子节点数字 5 与 4 比较,而后交换两个数字的位置
9、反复执行调整+交换步骤,直到整个序列有序

代码实现


template<typename Item>
class MaxHeap
{
    private: Item* data;
    int count;
    int capacity;

    void shiftUp(int k)
    {
        while( k>1 && data[k/2] < data[k])
        {
            swap(data[k/2],data[k]);
            k /= 2;
        }
    }

    void shiftDnow(int k)
    {
        while(2*k < count)  //当前k节点有子节点
        {
            int j = 2*k; //在此论循环中,data[k]和data[j]交换位置
            if( j+1 <= count && data[j+1]>data[j])
                j += 1;
            if(data[k] >= data[j])
                break;
            swap(data[k],data[j]);
            k=j;
        }
    }

    public:
        MaxHeap(int capacity)
        {
            data = new Item[capacity +1];
            count = 0;
            this->capacity = capacity;
        }
    // 构造函数, 通过一个给定数组创建一个最大堆
    // 该构造堆的过程, 时间复杂度为O(n)
        MaxHeap(Item arr[],int n)
        {
            data =new Item[n+1];
            capacity = 0;
            
            for(int i = 0;i < n;i++)
            {
                data[i+1] = arr[i];
                count = n;
            }
            for(int i = count/2;i >= 1;i**)
            {
                shiftDnow(i);
            }
            
        }
    
        int size()
        {
            return count;
        }
        bool isEmpty()
        {
            return count == 0;
        }
        void insert(Item item)
        {
            assert( count +1 <= capacity);
            data[count + 1] = item;
            count++;
            shiftUp(count);
        }

        Item extracMax()
        {
            assert(count > 0);
            Item ret = data[1];

            swap(data[1],data(count));
            count -- ;
            shiftDnow(1);
            return ret;
        }
        
            // 获取最大堆中的堆顶元素
        Item getMax()
        {
            assert( count > 0 );
            return data[1];
        }
};

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容