stl源码剖析 详细学习笔记heap

来源:互联网 发布:如何破解无壳网络验证 编辑:程序博客网 时间:2024/05/21 14:42

//

//  heap.cpp

//  笔记

//

//  Created by fam on 15/3/15.

//

//


//---------------------------15/03/15----------------------------



//heap

{

   /*

        heap概述:

        heap并不是stl的容器,只是priority queue(优先队列)的助手

        它允许用户以任意顺序插入容器,但是取出是,总是取出优先级最高的元素

        heap用的是很常见的堆结构,用数组来表示,采用堆排序的方法排序,时刻保持堆的特性

     */

    

    

    

    //push_heap

   template <class RandomAccessIterator>

   inline void push_heap(RandomAccessIterator first,

                          RandomAccessIterator last)

    {

        __push_heap_aux(first,last, distance_type(first),

                        value_type(first));

        

    }

    

   template <class RandomAccessIterator,class Distance, class T>

   inline void __push_heap_aux(RandomAccessIterator first,

                                RandomAccessIterator last, Distance*,T*)

    {

        __push_heap(first,Distance((last - first) -1), Distance(0),

                    T(*(last -1)));

    }

    

   template <class RandomAccessIterator,class Distance, class T>

   void __push_heap(RandomAccessIterator first, Distance holeIndex,

                     Distance topIndex, T value)

    {

        //取最后一个元素的父节点,先减1的原因是第一个节点时0

        //而不是1开始算的

        Distance parent = (holeIndex -1) / 2;

        

        //一直循环到当前节点等于根节点或者 父节点的值大于等于添加的值

       while (holeIndex > topIndex && *(first + parent) < value)

        {

            // 把父节点的值赋值给当前节点

            *(first + holeIndex) = *(first + parent);

            

           //当前节点变成父节点

            holeIndex = parent;

            

            //父节点变成父节点的父节点

            parent = (holeIndex -1) / 2;

        }

        //把值赋值给恰当的位置

        *(first + holeIndex) = value;

    }

    

    //push功能总结:push就是从最后一个元素开始一直和父节点比较,如果要插入的值(最后一个元素的值)

    //比较大就不断上移,直到达到堆的根

    

    //pop_heap

   template <class RandomAccessIterator>

   inline void pop_heap(RandomAccessIterator first,

                          RandomAccessIterator last)

    {

        __pop_heap_aux(first,last,value_type(first));

        

    }

    

    

   template <class RandomAccessIterator,class T>

   inline void __pop_heap_aux(RandomAccessIterator first,

                                RandomAccessIterator last, T*)

    {

        __pop_heap(first,last -1,last - 1, T(*(last -1))

                    distance_type(first));

    }

    

   template <class RandomAccessIterator,class T, class Distance>

   inline void __pop_heap(RandomAccessIterator first,

                           RandomAccessIterator last,

                           RandomAccessIterator result,

                           T value, Distance*)

    {

        *result = *first;

        __adjust_heap(first, Distance(0), Distance(last - first), value);

    }

    

    

   template <class RandomAccessIterator,class Distance, class T>

   void __adjust_heap(RandomAccessIterator first, Distance holeIndex,

                       Distance len, T value)

    {

        //topIndex == 0   -->>   topelem == first + 0

        Distance topIndex = holeIndex;

        

        //由于从0开始计算所以右儿子为 2n + 2;

        //secondChild 其实也是Index,不是真的值

        

        Distance secondChild =2 * holeIndex + 2;

        

        //只要右儿子存在就一直循环

       while (secondChild < len)

        {

            //如果有右儿子小于左儿子,secondChild就设置为左儿子

            //目的是要让当前节点最后成为2个节点中最大的

           if(*(first + secondChild) < *(first + (secondChild -1)))

                secondChild--;//为什么不是 --secondChild,这样效率更高

            

            //把当前节点的值设置为secondChild的值

            *(first + holeIndex) = *(first +secondChild);

            

            //当前节点切换成secondChild节点

            holeIndex = secondChild;

            

            //设置secondChild为右儿子

            secondChild =2* (secondChild + 1);

        }

        

        //存在左儿子(如果有右儿子就会一直循环,最后只有两种情况,一是当前节点到达叶子节点

        //一种情况是没有右儿子,但是有左儿子)

       if(secondChild == len)

        {

            //把左儿子的值赋给当前节点

            *(first + holeIndex) = *(first + (secondChild -1));

            

            //把当前节点切换成左儿子

            holeIndex = secondChild -1;

    

        }

        

        //把当初标记的最后的一个节点插入堆中( T(*(last - 1)  )

        __push_heap(first, holeIndex, topIndex, value);

        

       /*

            总结:把根节点输出到result所以就要不断把儿子往上移来填充

            填充到最后就会空缺一个节点(下面的往上移动总会有一个空缺的)

            所以最后要把最后的一个元素插入到堆前面去,也就是最后空缺的是原先

            最后面的位置,那就没影响了

            如果空缺的已经是最后的元素了,那就是对已经排序好的堆做排序(最后的元素

            已经比父节点大了,会马上排好.

        */

        

    }

    

    

    //sort

    

   template<class RandomAccessIterator>

   void sort_heap(RandomAccessIterator first,

                   RandomAccessIterator last)

    {

        

       while (last - first > 1)

        {

            pop_heap(first, last--);

        }

    }

    

    //结束后就是已经排序好的序列,就不是堆了

    

    

    

    //make_heap

    

   template<class RandomAccessIterator>

   inline void make_heap(RandomAccessIterator first,

                          RandomAccessIterator last)

    {

        __make_heap(first, last, value_type(first), distance_type(first));

    }

    

   template<class RandomAccessIterator,class T, class Distance>

   void    __make_heap(RandomAccessIterator first,

                        RandomAccessIterator last, T*,Distance*)

    {

        //判断边界情况,如果只有一个元素直接返回

       if(last - first < 2) return;

        

        //len==元素个数

        Distance len = last - first;

        

        //parent == 最后一个元素的父节点

        Distance parent = (len -2) / 2;

        

       while (true)

        {

            //一直循环,直到全部排序好,从最后的三角形(最后的元素,父节点,左儿子(如果有的话))

            //开始,直到根节点,就调整完毕了

            __adjust_heap(first, parent, len, T(*(first + parent)));

           if(parent == 0)return ;

            parent--;

        }

    }

    


    

    

}


0 0
原创粉丝点击