• 《算法图解》——第二章 选择排序


            第二章    选择排序

    1    内存的工作原理
    计算机就像是很多抽屉的集合体,每个抽屉都有地址。
    需要将数据存储到内存时,你请求计算机提供存储空间,计算机给你一个存储地址。需要存储多项数据时,有两种基本方式——数组和链表。
     
     

    2    链表

    数组中添加新元素很麻烦,预留只是权变措施,有两处缺点:

    ①额外请求的位置可能根本用不上,这将浪费内存。你没有使用,别人也用不了。

    ②超过内存之后,还是要转移。

    链表中的元素可存储在内存的任何地方。

    链表的每个元素都存储了下一个元素的地址,从而使一系列随机的内存地址串在一起。

    犹如寻宝游戏一样,在链表中添加元素很容易:只需将其放入内存,并将其地址存储到前一个元素中。

    因此,只要有足够的内存空间,就能为链表分配内存。链表的优势在插入元素方面。


    3    数组

    需要同时读取所有元素时,链表的效率很高。但如果你需要跳跃,链表的效率真的很低。

    数组则不同:你知道其中每个元素的地址。需要随机地读取元素时,数组的效率很高,因为可迅速找到数组的任何元素。在链表中,元素并非靠在一起的,你无法迅速计算出第五个元素的内存地址,而必须先访问第一个元素以获取第二个元素的地址,再访问第二个元素以获取第三个元素的地址,以此类推,直到访问第五个元素。

    练习

    2.1假设你要编写一个记账的应用程序。

    你每天都将所有的支出记录下来,并在月底统计支出,算算当月花了多少钱。因此,你执行的插入操作很多,但读取操作很少。该使用数组还是链表呢?

    链表;聊表读取速度慢,插入速度快。而且只有要随机访问元素时,链表的读取速度慢。但是要读取所有元素,这种情况下,聊表的读取速度并不慢。


    4   在中间插入

    使用链表插入元素很简单,只需要修改它前面的那个元素指向的地址。而使用数组时,则必须将后面的元素都向后移,数组同时还要考虑空间的问题。


    5   删除

    同样,链表更好,因为只要修改前一个元素指向的地址即可。使用数组时,删除元素后,必须将后面的元素都向前移,不过不同于插入,不用考虑空间的问题。

    下面是常见数组和链表操作的运行时间

    有两种访问方式:随机访问和顺序访问。顺序访问意味着从第一个元素开始逐个地读取元素。链表只能顺序访问:要读取链表的第十个元素,得先读取前九个元素,并沿链接找到第十个元素。随机访问意味着可直接跳到第十个元素。

    练习

    2.2 假设你要为饭店创建一个接受顾客点菜单的应用程序。这个应用程序存储一系列点菜单。服务员添加点菜单,而厨师取出点菜单并制作菜肴。这是一个点菜单队列:服务员在队尾添加点菜单,厨师取出队列开头的点菜单并制作菜肴。你使用数组还是链表来实现这个队列呢?

    链表;因为要执行插入操作,不需要执行查找,厨师总是从队列中取出第一个。

    2.3  我们来做一个思考实验。假设Facebook记录一系列用户名,每当有用户试图登录Facebook时,都查找其用户名,如果找到就允许用户登录。由于经常有用户登录Facebook,因此需要执行大量的用户名查找操作。假设Facebook使用二分查找算法,而这种算法要求能够随机访问——立即获取中间的用户名。考虑到这一点,应使用数组还是链表来存储用户名呢?

    有序数组;数组支持随机访问,二分查找算法的话还要是有序的。

    2.4 经常有用户在Facebook注册。假设你已决定使用数组来存储用户名,在插入方面数组有何缺点呢?具体地说,在数组中添加新用户将出现什么情况?

    数组插入的速度很慢。而且是二分查找,数组必须是有序的,那么添加一个新用户,都必须都数组进行排序。

    2.5 实际上,Facebook存储用户信息时使用的既不是数组也不是链表。假设Facebook使用的是一种混合数据:链表数组。这个数组包含26个元素,每个元素都指向一个链表。例如,该数组的第一个元素指向的链表包含所有以A打头的用户名,第二个元素指向的链表包含所有以B打头的用户名,以此类推。假设Adit B在Facebook注册,而你需要将其加入前述数据结构中。因此,你访问数组的第一个元素,再访问该元素指向的链表,并将Adit B添加到这个链表末尾。现在假设你要查找Zakhir H。因此你访问第26个元素,再在它指向的链表(该链表包含所有以z打头的用户名)中查找Zakhir H。请问,相比于数组和链表,这种混合数据结构的查找和插入速度更慢还是更快?你不必给出大O运行时间,只需指出这种新数据结构的查找和插入速度更快还是更慢。

    查找时,比链表快,数组慢;插入时,比数组快,但与链表相当。


    6    选择排序

    选择排序是一种灵巧的算法,但其速度不是很快,其运算时间为O(n*n)。

    代码(将数组元素按从小到大的顺序排列):

    ①先编写一个用于找到数组中最小元素的函数

    ②再进行排序

    def findSmallest(arr):                    #函数是找到数组中最小的元素
        smallest = arr[0]                     #用于存储最小的值,同时假定第一个元素是最小的
        smallest_index = 0                    #最小的值的索引,同时也假定最小值的索引是0
        for i in range(1, len(arr)):          #遍历数组中每一个元素,从第二个开始
            if arr[i] < smallest:             #如果第二个元素小于第一个元素
                smallest = arr[i]             #那么赋值给smallest
                smallest_index = i            #索引同样操作
        return smallest_index                 #返回数组中最小值的索引
    
    def selectionSort(arr):                   #选择排序函数
        newArr = []                           #一个列表用于保存
        for i in range(len(arr)):             #遍历每一个元素
            smallest = findSmallest(arr)      #用上面的函数找到最小值
    newArr.append(arr.pop(smallest))  #⭐⭐pop()函数用于移除列表中的一个元素(默认最后一个元素,这里是smallest),并且返回该元素的值。

    return newArrprint(selectionSort([5, 3, 6, 2, 10]))


     

    7    小结

    计算机内存犹如一大堆抽屉。
    需要存储多个元素时,可使用数组或链表。
    数组的元素都在一起。
    链表的元素是分开的,其中每个元素都存储了下一个元素的地址。
    数组的读取速度很快。
    链表的插入和删除速度很快。
    在同一个数组中,所有元素的类型都必须相同(都为int、double等)。

  • 相关阅读:
    socket实现一个简单的echo服务
    Netty实现丢弃服务协议(Netty4.X学习一)
    大型情感剧集Selenium:8_selenium网页截图的四种方法
    python原类、类的创建过程与方法
    Flask使用bootstrap为HttpServer添加上传文件功能
    充满含金量的一场云原生Meetup,入场券免费发送中……
    Hadoop伪分布式集群的安装部署
    从缓冲池命中率角度判断自己的MYSQL数据库是否需要扩容内存
    MySQL分区表概述
    如何防止mysql数据库被勒索
  • 原文地址:https://www.cnblogs.com/NEWzyz/p/8918165.html
Copyright © 2020-2023  润新知