• 几种简单的排序算法(二)基本排序算法


    各种排序整理

    速查:

    image


    以下的排序用python来实现,比较方便


    2、快排

    image

    这个图是真的棒!一定要给抄过来哈哈哈哈哈,特地放一下原地址


    a)、时间复杂度(重要)

    众所周知 快排的 平均时间复杂度最优时间复杂度 都是:O(nlogn),

    最坏情况下(元素基本有序):O( n^2 )

    b)、概念和实现

    快排(quick sort)采用了分治的思想,个人觉得用递归来概括也是可以的。

    思想:

    通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

    具体方法:

    1. 在数列之中,选择一个元素作为”基准”(pivot),或者叫比较值。(一般会选用 左1 元素)
    2. 数列中所有元素都和这个基准值进行比较,如果比基准值小就移到基准值的左边,如果比基准值大就移到基准值的右边
    3. 以基准值左右两边的子列作为新数列,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

    代码实现:

    def quickSort(targetlist, left ,right):
        if left>right:
            return
        pivot = targetlist[left]   # pivot是基准
        i = left
        j = right
        while(i < j):
            # 如果right一直大于pivot,则继续走 直到找到比pivot小的
            while(targetlist[j] >= pivot and i<j):
                j -=1
            while(targetlist[i] <= pivot and i<j):
                i+=1
            # 此时right < pivot,left > pivot, 将i和j做交换
            if(i < j): # 这里做判断是为了right到了left位置时,不用再将执行下面这三行代码了
                temp = targetlist[i]
                targetlist[i] = targetlist[j]
                targetlist[j] = temp
        # left和right相遇了
        # 将相遇点的元素和pivot做交换
        targetlist[left] = targetlist[j]
        targetlist[j] = pivot
        print(targetlist)
        # 对于基准点两边的元素分别在做排序
        quickSort(targetlist, left,j-1)    # 递归
        quickSort(targetlist, j+1,right)
    
    
    if __name__ == "__main__":
        target = [180,183,187,182,55,123,490,999,2]
        quickSort(target,0,len(target)-1)
        print(target)
    
    

    或者借用lambda表达式 一行代码...也行,下面代码结果是升序的

    quick_sort = lambda array: array if len(array) <= 1 else quick_sort([
        item for item in array[1:] if item <= array[0]
    ]) + [array[0]] + quick_sort([item for item in array[1:] if item > array[0]])
    
    target = [180,183,187,182,55,123,490,999,2]
    a = quick_sort(target)
    print(a)
    

    c)、总结(重要)

    1. 稳定性:快排是一种不稳定排序,比如基准值的前后都存在与基准值相同的元素,那么相同值就会被放在一边,这样就打乱了之前的相对顺序
    2. 比较性:因为排序时元素之间需要比较,所以是比较排序
    3. 时间复杂度:快排的时间复杂度为O(nlogn)
    4. 空间复杂度:排序时需要另外申请空间(改进算法不需要额外空间),并且随着数列规模增大而增大,其复杂度为:O(nlogn)
    5. 归并排序与快排 :归并排序与快排两种排序思想都是分而治之,但是它们分解和合并的策略不一样:归并是从中间直接将数列分成两个,而快排是比较后将小的放左边大的放右边,所以在合并的时候归并排序还是需要将两个数列重新再次排序,而快排则是直接合并不再需要排序,所以快排比归并排序更高效一些
    6. 快速排序有一个缺点就是对于小规模的数据集性能不是很好

    3、冒泡排序

    img

    冒泡排序是一种比较容易理解的排序算法,它重复的访问比较要排序的元素列,一次比较两个相邻的元素,一层一层的将较大的元素往后移动,这种类似气泡在上升过程中慢慢变大效果的排序就是冒泡排序

    a)、时间复杂度

    一般来说,因为它需要双层循环n*(n-1)),所以平均时间复杂度为O(n^2)

    改进后的算法这里不考虑。

    b)、概念和实现

    思想:

    1. 从第一个和第二个开始比较,如果第一个比第二个大,则交换位置,然后比较第二个和第三个,逐渐往后
    2. 经过第一轮后最大的元素已经排在最后,所以重复上述操作的话第二大的则会排在倒数第二的位置。
    3. 那重复上述操作n-1次即可完成排序,因为最后一次只有一个元素所以不需要比较

    代码实现:

    """冒泡排序"""
    def bubbleSort(targetlist):
        # 第一层for循环表示循环的遍数
        for i in range(len(targetlist) -1):
            # 第二层for表示具体比较哪两个元素
            for j in range(len(targetlist) -1 -i):
                if targetlist[j] > targetlist[j+1]:
                    # 如果前大后小,则交换
                    targetlist[j],targetlist[j+1] = targetlist[j+1],targetlist[j]
                    
    
    if __name__ == "__main__":
        target = [180,183,187,182,55,123,490,999,2]
        bubbleSort(target)
        print(target)
    
    

    c)、总结

    • 这是一种偏慢的排序算法,仅适用于对于含有较少元素的数列进行排序
    • 稳定性:只有当前一个元素大于后一个元素时候才会调换顺序,所以它是稳定的
    • 比较性:排序时候元素之间需要比较,所以是比较排序
    • 空间复杂度:只需要常数个辅助单元,所以空间复杂度为O(1),我们把空间复杂度为O(1)的排序成为原地排序(in-place)

    4、选择排序

    img

    没有找到更好的动图了好可惜


    选择排序(selection sort)是一种简单直观的排序算法。每次从待排序的数据元素中选出最小(最大)的一个元素,存放在序列的起始位置,故而称为 选择排序

    a)、时间复杂度

    选择排序同样是双层循环n*(n-1)),所以时间复杂度也为:O(n^2)

    b)、概念和实现

    思想:

    1. 设第一个元素为比较元素,依次和后面的元素比较,比较完所有元素找到最小的元素,将它和第一个元素互换
    2. 重复上述操作,我们找出第二小的元素和第二个位置的元素互换,以此类推找出剩余最小元素将它换到前面,即完成排序

    代码实现:

    该实现方法和冒泡方法有点像,都是双层循环

    """选择排序"""
    def selectionSsort(targetlist):
        # 第一层for表示循环选择的遍数
        for i in range(len(targetlist) - 1):
            # 将起始元素设为最小元素
            min_index = i
            # 第二层for表示最小元素和后面的元素逐个比较
            for j in range(i + 1, len(targetlist)):
                if targetlist[j] < targetlist[min_index]:
                    # 如果当前元素比最小元素小,则把当前元素角标记为最小元素角标
                    min_index = j
            # 查找一遍后将最小元素与起始元素互换
            targetlist[min_index], targetlist[i] = targetlist[i], targetlist[min_index]
    
    
    if __name__ == "__main__":
        target = [180,183,187,182,55,123,490,999,2]
        selectionSsort(target)
        print(target)
    

    c)、总结

    1. 稳定性:因为存在任意位置的两个元素交换,比如[5, 8, 5, 2],第一个5会和2交换位置,所以改变了两个5原来的相对顺序,所以为不稳定排序
    2. 比较性:因为排序时元素之间需要比较,所以是比较排序
    3. 空间复杂度:只需要常数个辅助单元,所以空间复杂度也为O(1)

    5、插入排序

    img

    插入排序(Insertion-Sort)的算法描述也是一种简单直观的排序算法。主要时通过构建有序序列,对于未排序的数据,在已排序序列中从后向前扫描,找到相应的位置再插入。就像是在书架中插书:先找到相应位置,将后面的书往后推,再将书插入,如上图所示。

    插入排序的适用场景:一个新元素需要插入到一组已经是有序的数组中,或者是一组基本有序的数组排序

    a)、时间复杂度

    插入排序同样需要两次循坏一个一个比较,故时间复杂度也为O(n^2)

    b)、概念和实现

    思想:

    1. 从第二个元素开始和前面的元素进行比较,如果前面的元素比当前元素大,则将前面元素 后移,当前元素依次往前,直到找到比它小或等于它的元素插入在其后面
    2. 然后选择第三个元素,重复上述操作,进行插入
    3. 依次选择到最后一个元素,插入后即完成所有排序

    举例:

    一次遍历排好一个元素

    比较次数 列表 操作
    原始序列 [180,183,187,182,55,123,490,999,2]
    第一次比较后 [180,183,187,182,55,123,490,999,2]
    第二次比较后 [180,183,187,182,55,123,490,999,2]
    第三次比较后 [180,182,183,187,55,123,490,999,2] 182从后往前同黄色序列比较
    第四次比较后 [55,180,182,183,187,123,490,999,2] 55
    第五次比较后 [55,123,180,182,183,187,490,999,2] 123
    第六次比较后 [55,123,180,182,183,187,490,999,2]
    第七次比较后 [55,123,180,182,183,187,490,999,2]
    第八次比较后 [2,55,123,180,182,183,187,490,999] 2

    代码实现:

    """插入排序"""
    def insertionSort(targetlist):
        # 第一层for表示循环插入的遍数
        for i in range(1, len(targetlist)):
            # 设置当前需要插入的元素
            current = targetlist[i]
            # 与当前元素比较的比较元素
            pre_index = i - 1
            # 将所有当前元素之前的且大于当前元素的元素向后移动
            while pre_index >= 0 and targetlist[pre_index] > current:
                # 比较元素大于当前元素则把比较元素后移
                targetlist[pre_index + 1] = targetlist[pre_index]
                # 向前选择下一个比较元素,继续比较
                pre_index -= 1
            # 经过上面的一系列挪动,当比较元素小于当前元素,则将当前元素插入在其后面
            targetlist[pre_index + 1] = current
    
    
    if __name__ == "__main__":
        target = [180,183,187,182,55,123,490,999,2]
        insertionSort(target)
        print(target)
    

    c)、总结

    • 需要区别于选择排序

    • 当一个新元素需要插入到一组已经是有序的数组中,或者是一组基本有序的数组排序(而快排则是基本无序的情况下使用的)

    • 其他特点

      • 比较性:排序时元素之间需要比较,所以为比较排序
      • 稳定性:从代码我们可以看出只有比较元素大于当前元素,比较元素才会往后移动,所以相同元素是不会改变相对顺序是稳定的
      • 空间复杂度:只需要常数个辅助单元,所以空间复杂度也为O(1)





    还有一些算法后面在更新,今天就先过掉这些基本算法





    (以上资料内容侵删)
    转载时请告知(以上资料内容侵删)
    每个人都知道的,哪怕已经很糟糕了但是努力生活依旧很重要。
  • 相关阅读:
    控制测试与实质性程序的关系
    【2020-02-23】一个生活视角的触发
    工作,拼的都是脏和累
    【2020-02-22】让偶然不再偶然
    【2020-02-21】当心自己的想象力
    【2020-02-20】想清楚,自己在为谁服务
    静态化与伪静态化的区别
    e3商城_day04
    e3商城_day03
    服务器,操作系统,虚拟机,虚拟主机,IP地址
  • 原文地址:https://www.cnblogs.com/ppppian2020/p/13110282.html
Copyright © 2020-2023  润新知