zoukankan      html  css  js  c++  java
  • 排序算法-选择排序/堆排序

    选择排序

    实现原理

    选择排序算法的实现思路有点类似插入排序,也分已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。图示如下:

    同样,可以在 VisuAlgo 上看动态图:https://visualgo.net/zh/sorting。

    示例代码

    选择排序的PHP实现代码如下:

    <?php
        
        /**
         * 选择排序算法实现
         */
        function selection_sort($nums)
        {
            if (count($nums) <= 1) {
                return $nums;
            }
        
            for ($i = 0; $i < count($nums); $i++) {
                $min= $i;
                for ($j = $i + 1; $j < count($nums); $j++) {
                    if ($nums[$j] < $nums[$min]) {
                        $min = $j;
                    }
                }
                if ($min != $i) {
                    $temp = $nums[$i];
                    $nums[$i] = $nums[$min];
                    $nums[$min] = $temp;
                }
            }
        
            return $nums;
        }
        
        $nums = [4, 5, 6, 3, 2, 1];
        $nums = selection_sort($nums);
        print_r($nums);
    
    

    性能分析

    • 很显然,选择排序的时间复杂度也是 O(n^2)
    • 由于不涉及额外的存储空间,所以是原地排序;
    • 由于涉及非相邻元素的位置交换,所以是不稳定的排序算法。

    综合比较前面介绍的三个排序算法,时间复杂度都是一样的,也都是原地排序,但是选择排序是不稳定的排序算法,此外,插入排序和冒泡排序相比较,我们在将插入排序的时候讲到,插入排序只需要一条语句,而冒泡排序需要三条,在同等条件下,或者数据量很大的情况下,插入排序性能是要优于冒泡排序的,所以综合比较下来,三者的优先级是插入排序 > 冒泡排序 >> 选择排序。

    堆排序(选择排序的一种)

    堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。
    可以利用数组的特点快速定位指定索引的元素。
    堆分为大根堆和小根堆,是完全二叉树。
    大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

    思路分析:堆排序利用了大根堆堆顶记录的关键字最大(或最小)这一特征

    PHP代码实现示例:

    class HeapSort
    {
        /**
         * @var int
         */
        protected $count;
    
        /**
         * @var array
         */
        protected $data;
    
        /**
         * HeapSort constructor.
         *
         * @param array $data
         */
        public function __construct(array $data)
        {
            $this->count = count($data);
            $this->data  = $data;
        }
    
        /**
         * Action
         *
         * @return array
         */
        public function run()
        {
            $this->createHeap();
            while ($this->count > 0) {
                /* 这是一个大顶堆 , 所以堆顶的节点必须是最大的
                   根据此特点 , 每次都将堆顶数据移到最后一位
                   然后对剩余数据节点再次建造堆就可以 */
                $this->swap($this->data[0], $this->data[--$this->count]);
                $this->buildHeap($this->data, 0, $this->count);
            }
            return $this->data;
        }
    
        /**
         * 创建一个堆
         */
        public function createHeap()
        {
            $i = floor($this->count / 2) + 1;
            while ($i--) {
                $this->buildHeap($this->data, $i, $this->count);
            }
        }
    
        /**
         * 从 数组 的第 $i 个节点开始至 数组长度为0 结束 , 递归的将其 ( 包括其子节点 ) 转化为一个小顶堆
         *
         * @param $data
         * @param $i
         * @param $count
         */
        public function buildHeap(array &$data, $i, $count)
        {
            if (false === $i < $count) {
                return;
            }
            // 获取左 / 右节点
            $right = ($left = 2 * $i + 1) + 1;
            $max   = $i;
            // 如果左子节点大于当前节点 , 那么记录左节点键名
            if ($left < $count && $data[$i] < $data[$left]) {
                $max = $left;
            }
            // 如果右节点大于刚刚记录的 $max , 那么再次交换
            if ($right < $count && $data[$max] < $data[$right]) {
                $max = $right;
            }
            if ($max !== $i && $max < $count) {
                $this->swap($data[$i], $data[$max]);
                $this->buildHeap($data, $max, $count);
            }
        }
    
        /**
         * 交换空间
         *
         * @param $left
         * @param $right
         */
        public function swap(&$left, &$right)
        {
            list($left, $right) = array ($right, $left);
        }
    }
    
    $array  = array (4, 21, 41, 2, 53, 1, 213, 31, 21, 423, 56);
    $result = (new HeapSort($array))->run();
    var_dump($result);
    
    
  • 相关阅读:
    iscsi: 多路径
    Paxos算法分析
    ceph实践: 搭建环境
    ocfs2: 搭建环境
    设计模式:Context模式
    Ceph剖析:Leader选举
    Ceph剖析:定时器safetimer的实现
    nfs:环境搭建
    Ceph剖析:数据分布之CRUSH算法与一致性Hash
    Linux命令小结:crontab/netstat/iostat/sar
  • 原文地址:https://www.cnblogs.com/stringarray/p/12704300.html
Copyright © 2011-2022 走看看