使用函数的选择法排序_计算机入门必备算法——选择排序法

1、引言

昨天我们学习了二分查找法,但是二分查找法使用的前提必须是有序的数组或者列表,(当然很多的算法都是仅再数据有序的前提下才能使用)

但是在实际工作中,我们接收到的数组不可能都是有序的,那怎么办呢?于是乎我们就应该先对接收到的数组或者列表进行排序。今天先来介绍第一种排序方法————选择排序。在要理解选择排序的内容,我们还必须具备关于数组、链表和大O表示法(专业术语:时间复杂度)的知识储备。

2、知识准备

我们都知道不管是数组还是链表,它们都是操作系统为我们开辟的一系列空间,但两者不同的是数组是一段连续的内存空间,而链表不连续。这两种内存空间都各有利弊,我们要视实际情况选择数组还是链表解决问题。首先,我们应对内存有一个直观的了解。

2.1.1 内存

我们都去超市买过东西,但是进入超市并不能携带我们的包或者其他物品,超市便提供了储物柜让我们存放物品,这个储物柜又分了很多小的储物箱。每个储物箱都只能放一件合适的东西,但你有两件东西,那怎么办呢?那我们就得向储物柜请求两个储物箱的位置。等到储物柜给你开好两个箱门时,你便可将东西存放起来。这大致上就是计算机内存的工作原理。

708b1d31ae4bbbf8a7feef7be8b753be.png

储物柜

当我们需要将数据存储到内存时,我们需要向操作系统请求存储空间,计算机会在内存空间允许的情况下,便会分配给你一个内存地址。同理当我们需要存储多项数据时,编程语言向我们提供了两种基本方式————数组和链表,正如上面所说,两者有不同之处且各有利弊。下面介绍数组和链表的相关知识。

2.1.2 数组

上面介绍到,当我们需要存储多项数据,便需要向操作系统请求一段内存空间。编程语言向我们提供了数组和链表两种方式,那么我们应该选择数组还是链表呢?上面介绍到数组是一段连续的内存空间,链表是不需要连续的,只需要每块内存中保留下一块内存的地址,于是乎这些地址块串联在一起,便形成了一段内存空间。

9b0e8384c90e931dc758e67fd1f8efdb.png

数组

但我们这节介绍数组,我们就举一个例子去讲解数组的存储方式。比如说你和室友去老食堂吃饭,现在只值军训期间,吃饭的人会非常多,你们转完了整个一层二层之后发现有一个桌子只坐了对面两人,于是乎你去问人家你们旁边还有人吗?人家要说没有你们就赶紧放下具有你们标志的东西就跑去买饭。买好之后正吃着饭又来了一个刚上完课的室友,于是乎你们得三人坐在一起,本来等旁边两人吃完了室友就可以坐下了,但是旁边的一直就吃个没停,那么我们就要重新寻找一个可以容纳三人的桌子,等找到之后你们就可以愉快的吃饭了!但如果再来一个和对象刚刚分开的室友,那你们就得炮轰他之后再次转移,真是吃饭都吃不安宁。同样的,在数组中添加新的元素也很麻烦,数组必须保证是一段连续的内存空间,如果这个空间不够用,那么就得需要重新申请,这样就很麻烦。有没有解决办法呢?是有的!如果你有能力承包整个餐厅的话,那么整个餐厅的桌子都是你的,你可以带上你的室友,你的对象,你对象的对象,你对象的对象......按顺序就坐。当然坐不满的话显然浪费了公共资源,如果不够坐的话你还得去承包新食堂用视频连线吃饭。如果你不想这样,那么就得请链表出山了!

2.1.3 链表

链表这个老大哥的话,它允许你把数组存储到内存的任何地方(可不连续)。但是如何找到下一个数据呢,那么就需要上一个数据携带下一个内存的地址,从而使得随机的内存串联在了一起。所以在链表上加入元素很容易,只需将其放入内存中,然后把地址存储到上一个元素中去。使用链表时,不需要去移动数据。

3441750bbc0a96952726c65cf2a2eab7.png

链表

举个简单例子在接力赛跑中,400米并没有找1000人(假设1000人的队伍有400米)去排队,然后到达终点。而现实并不是这样,如果是双人接力的话,那么安排两人(一个在起点,一个在跑道中央),那么就需要告诉起点的人,你的接力的人在哪里,才能将接力棒传给下一个人,但如果是四人接力,那么我们就得分别告诉每一个接力的人,它的下一个位置应在哪里。这个例子应该能够理解链表的存储方式,只要有足够的内存空间,就能为链表分配内存。

2.1.4 优缺点

数组的优点很明显就是读取数据,在于它天然的连续性,如果我们已知了数组存储的首地址,那么我们找任何一个数据都是很容易(数组是定长的),用大O表示法为O(1)。但我们需要注意的是数组中元素的索引是从0开始的,而不是1。从0开始让基于数组的代码编写起来很容易,因此程序员始终坚持这么做。

链表在读取数据时就显得有点吃不消,因为自己的地址不连续,那么就需要从第一个元素开始找第二个元素,然后根据第二个元素存的地址找到下一个元素,以此类推,找到我们需要找到的元素,如果我们所要寻找的元素是第一个时,真香!用大O表示法为O(n)。

但数组的缺点就很明显,就是上面所说的不好插入新元素,要么得等,要么就得重新申请。很麻烦,大O表示法为O(n)。链表这块就非常的容易,只需要保存到前一个元素中,就把新元素插入到了链表中。大O表示法为O(1)。

删除元素时,应选择哪个方式更好呢?这个问题留给你们思考。(留言哦~)

2.2 选择排序

对数组和链表有了整体的了解之后,就可以了解选择排序算法了。

2.2.1 选择排序的原理

还是用生活中的例子来解释选择排序的原理。我们都是老网抑云了,当我们听每首歌时,网易云后台都会收集每首歌的播放次数(当然我没有在网易云工作,纯属猜测,只是想举个栗子)。于是乎程序员需要对每一个用户喜爱播放的歌曲次数由多到少的进行排列,很容易想到的就是我再弄一个列表过来,每一次遍历这个次数列表,找出第一多的,放到我的新列表中去,然后在遍历次数列表,找出第二多,然后保存在新列表,循环往复,最后,我得到了一个有序列表(网易云员工应该不会这么排序,应该够程序员辞职好几回了)。

d37fd20ac110933afd2db10088b1bfe6.png

播放列表

2.2.2 代码实现

废话不多说,直接上代码。(代码都是编译通过且得出正确结果的,如果什么更好的写法的话,可以给我留言哦~)

/*    定义一个方法:取出数组中的最小值的索引    数组为int型数组     */    private static int GetSmallValue(List arr)    {        //定义一个变量用于接受数组中第一个值,这个值以后用来返回数组中最小的值        int smallest = arr.get(0);        //定义一个变量用来存储数组中第一个值的索引,这个变量以后用来接收数组中最小值的索引        int smallestIndex = 0;        //遍历数组        for(int i = 1 ; i < arr.size() ; i++)        {            //如果数组中的某一个元素小于我们最初定义的值,那么我们要修改最小值变量            if(arr.get(i) < smallest)            {                smallest = arr.get(i);                //赋值最小值索引                smallestIndex = i;            }        }        return smallestIndex;    }    /*    选择排序:    每次执行获取数组最小值的方法,选出数组中最小的那个值之后,然后插入到新的数组中,    从而可以得到新的有序数组     */    private static int[] SelectSort(Integer[] arr)    {        List list = Arrays.asList(arr);        List arrList = new ArrayList<>(list);        System.out.println(arrList.size());        int[] newArr = new int[arr.length];        //执行获取最小值的方法,插入到新数组中        for(int i = 0; i

2.2.3 运行时间

我们来分析一下这个排序算法的运行时间,我们首先需要对列表进行一次简单查找(上一节的傻找),它的运行时间为O(n)。你要找完列表的所有大,那么你需要执行n次。需要的总时间就很容易得到为O(n x n) = O(n²)。这样的算法有点简单粗暴,当然这能说明问题。具体怎么得出我也不会,留给你们吧~你们一定比我聪明!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值