zoukankan      html  css  js  c++  java
  • stl源码剖析 详细学习笔记heap

    //

    //  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--;

            }

        }

        


        

        

    }


  • 相关阅读:
    Maybe You Don't Know ! 如何比较两个引用是否指向同一个对象?
    记录一点项目心得...
    SharePoint 站点模版
    ObjectSpaces,See you in 2006...
    CLR如何实现线程同步
    Using 1.1, Waiting 2.0 & EasyThread
    在SharePoint中的Workflow引擎开发完成
    ViewState
    《WalkThrough WebPart 入门指南二》完成
    隐藏在.NET中的IoC?
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983170.html
Copyright © 2011-2022 走看看