算法入门三——选择排序算法

Posted 夕水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法入门三——选择排序算法相关的知识,希望对你有一定的参考价值。

在理解选择排序算法的原理之前,我们需要了解大O表示法,数组与链表等概念。


一.计算机内存工作原理


经常与计算机接触,相信都会听到内存这一个词,那么何为内存呢?我们用一个很形象的比喻来说明这个问题。


假设有一个柜子,柜子有很多抽屉,每个抽屉能放一些东西。也就是说,当我们往抽屉里放东西的时候,柜子就保存了这些东西。一个东西放一个抽屉,两个东西放两个抽屉。计算机内存的工作原理就如此,计算机的内存更像是许多抽屉的集合



二.数组


数组就是一系列元素的列表集合。比如,你要写一个待办事项的应用程序(前端术语也可以说是todolist)。那么你就需要将许多待办事项存储到内存中。使用数组意味着内存是紧密相连的,为何如此说呢?


数组的元素自带编号,每个元素的位置,我们也叫做索引。例如:

[10,20,30,40]这一个数组,元素20的索引或者说所处的位置是1。因为数组的编号都是从0开始的,这可能会让很多新手程序员搞不明白。几乎所有编程语言对数组的编号都是从0开始的,绝对不止javascript这一门语言。


假设,你要为以上[10,20,30,40]再添加一个元素,很明显,利用JavaScript提供的数组方法,你只能在之前或者最末又或者中间插入元素。但在内存中却不是这样。还是用一个比喻来说明。


相信每个人都有看电影的经历,试想当你到了电影院之后,找到地方之后就坐下,然后你的朋友来了,本想靠着你坐,但是靠着你的位置都被人占领了。你的朋友就不得不转移位置,在计算机中,请求计算机重新分配一个内存,然后才能转移到另一个位置。如此一来,添加新元素的速度就会很慢。


那么,有没有办法解决呢?


似乎,很多人都这样做过,由一个人占领位置之后,然后把旁边的预留座位也给占领,不仅仅是在电影中,在公交车上抢座位也是如此。这种办法,我们暂且称之为"预留座位"。


这在计算机中也同样适用。我们在第一次请求计算机分配内存的时候,就请求计算机分配一些空余的内存,也就是"预留座位"出来。假定有20个"预留座位",这似乎是一个不错的措施。但你应该明白,这个措施,也存在缺点:


  1. 你额外请求的位置有可能根本就用不少,还将浪费内存。比如你选了座位,结果你的朋友没有来,其他人也不知道你的朋友不会来,也就不会坐上去,那么这个座位就空下来了。

  2. 如果来的人超过了20个之后,你预留的座位又不够,这就不得不继续重新请求转移。


针对这种问题,我们可以使用链表来解决。


三.链表




而且,使用链表还不用移动元素。因为只要有足够的内存空间,计算机就能为链表分配内存。比如如果你要为数组分配100个位置,内存也仅有100个位置,但元素不能紧靠在一起,在这样的条件下,我们是无法为数组分配内存的,但链表却可以。


链表好像自动就会说,“好吧,我们分开来坐这些位置”。


但链表也并非没有缺点。我们再做一个比喻:


假如你看完了一本小说的第一章觉得第一章不好看,想跳过几章去看,但并没有这样的操作,因为一般都是下一章下一章的看的,这意味着你要看第五十章,就要点下一章49次,这样真的很烦。(点目录不算)




利用大O表示法,我们可以表示将数组和链表的运行时间表示出来,如下:

         数组   链表

读取: O(1)    O(n)

插入: O(n)    O(1)


其中O(1)称作常量时间,O(n)则是线性时间。



那么问题来了,数组与链表究竟哪种数据结构用的最多呢?


要看情况。但数组显然用的更多,因为数组支持随机访问。元素的访问有两种方式:顺序访问随机访问。顺序访问意味着 你需要挨着顺序一个一个的访问元素,而随机访问这不必如此。因为数组有编号,所以在随机访问上,数组更能体现它的优势。


有了前面的知识,现在,咱们来学习选择排序算法吧!


四.选择排序法


假设你的计算机存储了一些视频,对于每个视频的 播放次数,你都做了记录,比如:

视频1:50

视频2:35

视频3:25

视频4:55

视频5:60


现在,你要做的就是将播放次数从少到多按顺序排列出来。该如何做呢?


首先,你肯定需要遍历这个列表,找出播放次数最少的,然后添加到新的一个列表中去,并将这个添加的元素在原来列表中删除,然后,你再次这样做,将播放次数第二少的找出来,依次类推……


最后,你就会得到一个有序列表


视频3:25

视频2:35

视频1:50

视频4:55

视频5:60


编写代码如下:

//用一个数组表示播放次数即可

var arr = [50,35,25,55,60];

// 编写一个函数,参数传入排序的数组

function selectSort(arr){

    //获取传入数组的长度

    var len = arr.length;

    //定义最小索引与数组每一项元素变量

    var minIndex,ele;

    for(var i = 0;i < len - 1;i++){

            //最小索引等于当前i值,相当于初始化值

            minIndex = i;

            //初始化每一项

            ele= arr[i];

         for(var j = 1;j < len;j++){

                //获取相邻数,比较大小,得到最小数索引

                if(arr[j] < arr[minIndex]){

                        minIndex = j;

                }

         }

         //将得到的最小数排列在最前面

        arr[i] = arr[minIndex];

        //与最小数做比较的值放在最小数所处的位置

        arr[minIndex] = ele;

    }

    return arr;

}

测试:

selectSort(arr);//[25,35,50,55,60]


下面我们来测试一下代码运行时间。对每个元素进行查找时,意味着每个元素都要查找一次,所以运行时间为O(n),需要找出最小元素,又要检查每个元素,这意味着又要O(n)的运行时间。因此需要的总时间为O(nxn)=O(n^2)。这也就是说,需要执行n次操作。


选择排序只是一种很灵巧的算法,但还称不上速度最快,速度最快的是快速排序法。下一次会提到。


以上是关于算法入门三——选择排序算法的主要内容,如果未能解决你的问题,请参考以下文章

快速排序从入门到精通

入门 | 经典排序算法—插入排序 & 选择排序

算法入门||第一节 选择排序

排序算法入门之选择排序-Java实现

算法入门五——快速排序算法(中)

计算机入门必备算法——选择排序法