问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

php 算法 堆排序

发布网友 发布时间:2022-04-22 23:00

我来回答

5个回答

懂视网 时间:2022-04-28 15:29

堆(heap)是计算机科学中一类特殊的数据结构的统称,通常是一个可以被看做一棵树的数组对象。

堆{k1,k2,ki,…,kn} (ki <= k2i,ki <= k2i+1)|(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)

关于堆:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树(下面)。
  • 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
  • 完全二叉树

    说到堆排序,就不能不提完全二叉树,这些基本概念在网上到处都是,我摘了个最简单的。。

    完全二叉树:除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点。

    我自己总结认为,正是因为有下面两个特点,

  • 只允许最后一层有空缺结点且空缺在右边,即叶子结点只能在层次最大的两层上出现(存储方式的规则性);
  • 若i>1,tree的双亲为tree[i p 2](其父子结点值的规律性);
  • 才使得其进行排序非常方便。

    堆排序

    堆排序求升序用大顶堆,求降序用小顶堆。

    本例用求降序的小顶堆来解析。

    堆排序步骤如下:

    1、我们将数据(49、38、65、97、76、13、27、50)建立一个数组$arr;

    2、用数组$arr建立一个小顶堆(主要步骤,会在代码注释里解释,下图是用一个数组建立小顶堆的过程);

    3、将堆的根(最小的元素)与最后一个叶子交换,并将堆长度减一,跳到第二步;

    4、重复2-3步,直到堆中只有一个结点,排序完成。

    堆排序的PHP实现


    //因为是数组,下标从0开始,所以,下标为n根结点的左子结点为2n+1,右子结点为2n+2; 
    //初始化值,建立初始堆
    $arr=array(49,38,65,97,76,13,27,50);
    $arrSize=count($arr);
    
    //将第一次排序抽出来,因为最后一次排序不需要再交换值了。
    buildHeap($arr,$arrSize);
    
    for($i=$arrSize-1;$i>0;$i--){
     swap($arr,$i,0);
     $arrSize--;
     buildHeap($arr,$arrSize); 
    }
    
    //用数组建立最小堆
    function buildHeap(&$arr,$arrSize){
     //计算出最开始的下标$index,如图,为数字"97"所在位置,比较每一个子树的父结点和子结点,将最小值存入父结点中
     //从$index处对一个树进行循环比较,形成最小堆
     for($index=intval($arrSize/2)-1; $index>=0; $index--){
     //如果有左节点,将其下标存进最小值$min
     if($index*2+1<$arrSize){
     $min=$index*2+1;
     //如果有右子结点,比较左右结点的大小,如果右子结点更小,将其结点的下标记录进最小值$min
     if($index*2+2<$arrSize){
     if($arr[$index*2+2]<$arr[$min]){
      $min=$index*2+2;
     }
     }
     //将子结点中较小的和父结点比较,若子结点较小,与父结点交换位置,同时更新较小
     if($arr[$min]<$arr[$index]){
     swap($arr,$min,$index);
     } 
     }
     }
    }
    
    //此函数用来交换下数组$arr中下标为$one和$another的数据
    function swap(&$arr,$one,$another){
     $tmp=$arr[$one];
     $arr[$one]=$arr[$another];
     $arr[$another]=$tmp;
    }

    下面是排序的最终结果:

    堆用来进行全排序,时间复杂度是O(nlogn)

    而快排用来全排序,平均时间复杂度也是O(nlogn)

    但堆排序可以用来求 TopK 时,堆的时间复杂度为O(Klog2(n),因为它只需要进行 K 轮排序即可。

    推荐教程:《PHP》

    热心网友 时间:2022-04-28 12:37

    1.目前为止专门为了一个算法出本书的很少见;
    2.PHP的算法与C++语言算极为相似,堆算法也是一样;
    3.给你一段代码:

    <?php
    /**
    php堆排序实现原理

    php程序中关于堆的一些概念:
    假设n为当前数组的key则
    n的父节点为 n>>1 或者 n/2(整除);
    n的左子节点l= n<<1 或 l=n*2,n的右子节点r=(n<<1)+1 或 r=l+1
    */
    $arr=array(1,8,7,2,3,4,6,5,9);
    /*
    数组$arr的原形态结构如下:
    1
    / \
    8 7
    / \ / \
    2 3 4 6
    / \
    5 9
    */
    heapSort($arr);
    print_r($arr);
    /*
    排序后生成标准的小顶堆结构如下:
    1
    / \
    2 3
    / \ / \
    4 5 6 7
    / \
    8 9
    既数组:array(1,2,3,4,5,6,7,8,9)
    */
    function heapSort(&$arr)
    {
    //求最后一个元素位
    $last=count($arr);
    //堆排序中通常忽略$arr[0]
    array_unshift($arr,0);

    //最后一个非叶子节点
    $i=$last>>1;

    //整理成大顶堆,最大的数整到堆顶,并将最大数和堆尾交换,并在之后的计算中忽略数组后端的最大数(last),直到堆顶(last=堆顶)
    while(true)
    {
    adjustNode($i,$last,$arr);
    if($i>1)
    {
    //移动节点指针,遍历所有非叶子节点
    $i--;
    }
    else
    {
    //临界点last=1,既所有排序完成
    if($last==1)break;
    //当i为1时表示每一次的堆整理都将得到最大数(堆顶,$arr[1]),重复在根节点调整堆
    swap($arr[$last],$arr[1]);
    //在数组尾部按大小顺序保留最大数,定义临界点last,以免整理堆时重新打乱数组后面已排序好的元素
    $last--;
    }
    }
    //弹出第一个数组元素
    array_shift($arr);
    }
    //整理当前树节点($n),临界点$last之后为已排序好的元素
    function adjustNode($n,$last,&$arr)
    {
    $l=$n<<1; //$n的左孩子位

    if(!isset($arr[$l])||$l>$last) return ;
    $r=$l+1; //$n的右孩子位
    //如果右孩子比左孩子大,则让父节点的右孩子比
    if($r<=$last&&$arr[$r]>$arr[$l]) $l=$r;
    //如果其中子节点$l比父节点$n大,则与父节点$n交换
    if($arr[$l]>$arr[$n])
    {
    //子节点($l)的值与父节点($n)的值交换
    swap($arr[$l],$arr[$n]);
    //交换后父节点($n)的值($arr[$n])可能还小于原子节点($l)的子节点的值,所以还需对原子节点($l)的子节点进行调整,用递归实现
    adjustNode($l,$last,$arr);
    }
    }

    //交换两个值
    function swap(&$a,&$b)
    {
    $a=$a ^ $b; $b=$a ^ $b; $a=$a ^ $b;
    }

    ?>

    4.对于以上代码希望对你有所帮助,其实我也没弄得很明白,因为这个算法实在有许多精妙之处,如果楼主有哪日更好的,请不惜赐教

    热心网友 时间:2022-04-28 13:55

    PHP里面的数据结构只有数组,没有堆。。。。

    高深的算法需要你有很好的数学基础

    热心网友 时间:2022-04-28 15:30

    实践,多写代码,有问题时才能明白

    热心网友 时间:2022-04-28 17:21

    自己都不会啊
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    人大政协辅助岗是什么 政务辅助人员是干什么 政府辅助人员是什么 努比亚的海拔什么意思 北非努比亚现在怎么样了啊 相邻权的相关法律 梦见老公离世了什么预兆 梦见自己老公走掉 你出轨后 怎么操作才没被发现? 评评怎么造句 川剧变脸,最多变几张脸?回几张呢? 川剧的变脸是怎么做到? php中的sort()函数 是什么算法? 用保温杯泡茶,真的有害健康吗? 在php中怎么排序键值数组 php数组怎样排序 order by 保温杯泡茶易致癌,这是真的吗,有什么影响呢? 保温杯泡茶易致癌,这是真的吗,为什么? 最常见的算法,用PHP如何实现 使用PHP描述冒泡排序和快速排序算法,对象可以是一个数组 今年后期苹果行情会涨吗 php冒泡排序法~呢? PHP数组排序array_multisort函数详细用法跟排序方法是怎样的?_百度知 ... 保温杯泡茶的危害到底有多大? 现在的苹果出口市场行情怎么样?求大神帮助 php如何按数组键值排序? 年后,各地苹果行情如何? 苹果市场价多少 php中对一组数字从大到小排序方法 供求理论分析为什么苹果在消费旺季价格下降,海边别墅却在消费旺季价格上升 四川川剧中变脸到底是怎么一回事?求详细解说! 是不是保温杯泡茶不好? 教一些最简单的川剧变脸方法 保温杯为何泡茶不好? 川剧变脸是怎么变的? 用保温杯泡茶好么 “川剧变脸揭秘”的过程和原理是什么? 保温杯泡茶叶好不好 川剧中变脸的秘密是什么? 川剧变脸到底是如何变的? 川剧变脸是国家二级机密吗? 如何看待「川剧变脸」是国家二级机密? 川剧变脸的原理和方法 川剧变脸有什么诀窍? 川剧变脸是怎么变的 川剧变脸怎么变的? 川剧变脸是什么原理 变脸是什么剧的绝活? 谁能告诉我川剧变脸的揭秘啊 最好详细点 谢谢 曼哈顿球怎么玩法???