[leetcode]排序算法(冒泡排序,选择排序,插入排序,快速排序,计数排序)(代码片段)

是安澜啊 是安澜啊     2023-02-24     551

关键词:

目录

1.冒泡排序

原理

 代码(python&cpp)

拓展:timeit()用法

2.选择排序

原理

3.插入排序

原理

代码(python&cpp)

4.归并排序

原理

代码

 5.快速排序

原理

代码(python&cpp)

6.计数排序

原理

 代码(python&cpp)

总结

参考


1.冒泡排序

冒泡排序(Bubble Sort)是一种很原始的排序方法,就是通过不断地交换“大数”的位置达到排序的目的。因为不断出现“大数”类似于水泡不断出现,因此被形象地称为冒泡算法。

原理

冒泡算法的基本原理就是比较相邻两个数字的大小。将两数中比较大的那个数交换到靠后的位置。不断地交换下去就可以将最大的那个数放到队列的尾部。然后重头再次交换,直到将数列排成有序数列。

一个 n 个数的数列需要排序 n -1轮。这样可以确保得到一个有序的数列。因此冒泡排序的时间复杂度是

 代码(python&cpp)

#!/user/bin/env/python3
#-*-conding:utf-8 -*-
# data:20211210
# author:yang

import random
import timeit

def randomList(n):
    """返回一个长度为n的整数列表,数据范围为[0,1000)"""
    iList = []
    for i in range(n):
        iList.append(random.randrange(1000))
    return iList

def bubbleSort(iList):
    """冒泡排序"""
    if len(iList) <= 1:
        return iList
    for i in range(1,len(iList)):
        for j in range(0,len(iList)-i):
            if iList[j] >= iList[j+1]:
                iList[j],iList[j+1] = iList[j+1],iList[j]
        print("第%d轮排序结果"%i,end=" ")
        print(iList)
    # return iList             


if __name__=="__main__":
    iList = randomList(10)
    print("iList:",iList)
    print(bubbleSort(iList))
    # bubbleSort(iList)
    # print(timeit.timeit("bubbleSort(iList)","from __main__ import bubbleSort,iList", number=100))
       

cpp待补充 

拓展:timeit()用法

python中的timeit()方法, 它用于获取代码的执行时间。该库将代码语句默认运行一百万次,并提供从集合中花费的最短时间,可以用来检查代码的性能。

语法:

timeit.timeit(stmt, setup,timer, number)

参数:

stmt:这将采用您要测量其执行时间的代码。默认值为“pass”。

setup:这将包含需要在stmt之前执行的设置详细信息。这个参数可以将stmt的环境传进去。比如各种import和参数什么的。默认值为“ pass”。

timer:它将具有计时器值,timeit()已经设置了默认值,我们可以忽略它。

number:stmt将按照此处给出的编号执行。默认值为1000000。

注:

要使用timeit(),我们需要导入模块,如下:

import timeit

另外需要补充一点是,如果你想直接 stmt 那里执行函数。可以把函数申明在当前文件中,然后在 stmt = ‘func()’ 执行函数。然后使用 setup = ‘from __main__ import func’ 即可,如果要import 多个需要使用 setup = from __main__ import func; import simplejson'

2.选择排序

原理

简单地说,选择排序只做了一件事,就是从数列中选择最大(最小)的那个数,将这个数放到合适的位置。然后在抛开这个数的子数列中找最大(最小)的那个数放到合适的位置。然后……一直到子数列为空为止。与冒泡排序稍有不同的是,它不是相邻的两个数比较,而是某个数和数列中其他所有的数比较。

第一轮排序:以数列中第1个数为基数,遍历数列中其他的数字,找到最小的那个数,然后交换这两个数的位置。 本轮排序的结果将数列中最小的那个数放到了数列的第一位。

 第二轮排序:然后以数列中的第2个数为基数,遍历数列中剩余的其他数字,找到最小的那个数,交换这两个数的位置。第二个数字3已经是剩余数列中最小的数了。因此本轮无须交换数字,

 第N轮排序:按照这个规律,不断地找剩余数列中最小的数字,交换位置,直到将原始数列排成有序数列。

选择排序数列完毕。共6个数,排序了5轮。理论上来说,选择排序的时间复杂度是 O ( n 2 )。但在Python中稍微有点特殊,因为Python 列 表 中 寻 找 最 小 的 那 个 数 不 需 要 逐 个 比 较 , 使 用min(iList[i:])就可以得到最小的那个数,所以使用Pythonic风格版本的选择排序,时间复杂度是 O ( n )。因此,理论上在Python版本的排序算法中选择排序算法是最快的。

 代码(python&cpp)

#!/user/bin/env/python3
#-*-conding:utf-8 -*-
# data:20211210
# author:yang

from randomList import randomList
import timeit

def selectionSort(iList):
    if len(iList) <= 1:
        return iList
    for i in range(0,len(iList)-1):
        if iList[i] != min(iList[i:]):
            minIndex = iList.index(min(iList[i:]))  # 最小数的下标
            iList[i],iList[minIndex] = iList[minIndex],iList[i]
    print("第%d轮排序结果:"%(i+1),end=" ")
    print("ilist:",iList)
    # return iList

if __name__ == "__main__":
    iList = randomList(10)
    print(iList)
    print(selectionSort(iList))
    # print(timeit.timeit("selectionSort(iList)","from __main__ import selectionSort,iList",number = 1)) 

cpp待补充 

3.插入排序

插入排序(Insertion Sort)可能是最容易理解的排序了,插入排序方法与打扑克取牌的排序很相似。在打扑克时,每取一张新牌,都会与手上已有的牌进行比较,将新牌插入到比自己小的牌后面。在取完所有的牌后,手上已有的牌就是个有序的序列。

原理

插入排序首先将数列分成两部分。数列的第一个数为left部分,其他的数为right部分。然后将right部分中的数逐一取出,插入left部分中合适的位置。当right部分为空时,left部分就成为了一个有序
数列。

举例:

 第一轮:

首先要做的是将数列分成左、右两部分,left部分是第一个数字,right部分是数列剩余的部分。首先在牌堆中取出第一张牌,牌面是7,

 第二轮排序

然后从牌堆中取出第二张牌,牌面是3。将牌面是3的牌放入手中合适的位置。将right部分的第一个数字3插入left部分合适的位置。3比7要小,插入到7的前面。

第N轮排序 

循环将right部分的数字插入left部分,插入排序的时间复杂度是 O ( n 2 )。

代码(python&cpp)

#!/user/bin/env/python3
#-*-conding:utf-8 -*-
# data:20211210
# author:yang

from randomList import randomList
import timeit

def insertSort(iList):
    if len(iList) <= 1:
        return iList
    for right in range(1,len(iList)):
        target = iList[right]
        for left in range(0,right):
            if target <= iList[left]:
                # 使用python切片赋值 
                iList[left+1:right+1] = iList[left:right] 
                iList[left] = target
                break
    return iList  

if __name__ == "__main__":
    iList = randomList(10)
    print(iList)
    print(insertSort(iList))
    # print(timeit.timeit("selectionSort(iList)","from __main__ import selectionSort,iList",number = 1))
    
        

cpp待补充 

4.归并排序

归并排序(Merge Sort)是一种典型的递归法排序。它把复杂的排序过程分解成一个简单的合并子序列的过程。至于怎么得到这个子序列,就得自己调用自己了。

原理

归并排序首先要做的就是将数列分成左右两部分(最好是等分),然后将左、右两个子数列排序完毕后再合并到一起就成了一个有序数列。左、右两个子数列怎么变成有序数列呢?那就回头调用自
己,再把子数列分成左、右两部分,直到将所有的子数列的长度分为1为止。然后把子子数列排序完毕后合并成子数列……有点像那个著名的故事,山上有座山,山里有座庙,庙里有两个和尚……。和尚讲故事是无穷无尽的,幸运的是数列的长度即使再大也不会是无尽的。所以当子子子……序列分到不可再分割的时候(最小的序列长度为1时),就可以返回开始合并数列了。逐步合并子子子子……数列,到最后就得到了一个新的有序数列。

第一次分组

第二次分组

 

经过三次分组,已经将所有的子子子数列都变成了长度为1的数列。现在可以确定这些长度为1的数列必定是有序数列了,然后开始反向合并这些数列。

第一次合并

这里还需要考虑left和right长度不一致的情况。先合并数列[3]、[5]以及[9]、[4]。

第二次合并 

 第三次合并

归并排序完毕。经过3次合并,最终得到了一个有序数列。归并排序的时间复杂度是 O ( n Log n) )。

代码

#!/user/bin/env/python3
#-*-conding:utf-8 -*-
# data:20211210
# author:yang

from randomList import randomList
import timeit

def mergeSort(iList):
    if len(iList) <= 1:
        return iList
    middle = len(iList)//2
    left,right = iList[0:middle],iList[middle:]
    return mergeList(mergeSort(left),mergeSort(right))

def mergeList(left,right):
    """合并序列"""
    mList = []
    while left and right:
        if left[0] >= right[0]:
            mList.append(right.pop(0))
        else:
            mList.append(left.pop(0))
            
    while left:
        mList.append(left.pop(0))
    while right:
        mList.append(right.pop(0))
    return mList   
    
if __name__ == "__main__":
    iList = randomList(10)
    print(iList)
    print(mergeSort(iList))
    # print(timeit.timeit("selectionSort(iList)","from __main__ import selectionSort,iList",number = 1))
               

 5.快速排序

快速排序(Quick Sort)算法也是一种递归排序,用简单的方法来解决复杂的问题,唯一不太好的地方就是稍微有点浪费空间。

原理

以列表中的任意一个数为基准(一般选择列表中的第一个数),将列表分为左、右(前、后)两个子列表:左边子列表的数要比基准数小,右边子列表的数要比基准数大。然后继续把左边子列表和右边子列表按同样的方法继续分解、比较,一直到分无可分为止。然后按照左边子列表(比基准数小)+基准数+右边子列表(比基准数大)的方式连接起来。最后得到一个有序的数列。

以数列[7,3,5,1,9,4]为例。

第一次分组

以“7”为基准,比7小的分在左边的子数列中,比7大的分在右边的子数列中。

 此时左边的子序列有4个数[3, 5, 1, 4],还需要继续分组。右边的子序列中只有一个数9,不需要再分了。第二次只需要将左边的部分分组排序就可以了。

第二次分组

左边的子序列还剩下[3, 5, 1, 4],现在以第一个数3为基准数,将后面部分的[5, 1, 4]分成两部分。同样还是比基准数(3)小的放到左边子序列,比基准数(3)大的放到右边子序列。

 数分组完毕后。只要按照一定的顺序重新组合起来就可以了。组合很简单,就是小的数(左边部分)+中间数(基准数)+大的数(右边部分)。

第一次合并

将子序列合并,具体规则是left + [base] + right。这里需要稍微注意一下,left和right都是序列(列表),而base部分是单独的一个数,所以需要将它序列化。

 第二次合并

 第三次合并

 经过3次分组、合并后,得到了有序数列。快速排序的时间复杂度最坏的情况下是 O ( n 2 )。

代码(python&cpp)

#!/user/bin/env/python3
#-*-conding:utf-8 -*-
# data:20211210
# author:yang

from randomList import randomList
import timeit

def quickSort(iList):
    if len(iList) <= 1:
        return iList
    left = []
    right = []
    for i in iList[1:]:
        if i <= iList[0]:
            left.append(i)
        else:
            right.append(i)
    return quickSort(left) + [iList[0]] + quickSort(right)
        

if __name__ == "__main__":
    iList = randomList(10)
    print(iList)
    print(quickSort(iList))
    # print(timeit.timeit("selectionSort(iList)","from __main__ import selectionSort,iList",number = 1))

注:此方法速度快。

6.计数排序

计数排序(Counting Sort)算法是一种比较特殊的算法,因为它不是一个基于比较的算法。将两个数进行比较,将大的数放后面、小的数放前面,这样的算法都是基于比较的算法。

原理

它采用了一个巧妙的方法,选择一个数为基数,然后统计整个数列中有多少个数比基数小。如果有 n 个数比基数小,那么基数就放到新数列的第n +1的位置上(rList[n])。以数列[7, 3, 5, 1, 9, 4]为例,首先要做的是先创建一个与[7, 3, 5, 1, 9, 4]相同长度的空数列。

 第一个数的位置

第二个数的位置

 

第三个数的位置

 

依次类推

将所有的数字都插入到新数列后,排序就完成了。计数排序的时间复杂度是 O ( n + k ),其中 k 是整数的范围。

 代码(python&cpp)

#!/user/bin/env/python3
#-*-conding:utf-8 -*-
# data:20211210
# author:yang

from randomList import randomList
import timeit

def countingSort(iList):
    if len(iList) <= 1:
        return iList
    iLen = len(iList)
    rList = [None]*iLen
    for i in range(iLen):
        small = 0   # 比基数小的
        same = 0    # 与基数相等的
        for j in range(iLen):
            if iList[j] < iList[i]:
                small += 1
            elif iList[j] == iList[i]:  # 相同的数
                same += 1
        for k in range(small,small+same):
            rList[k] = iList[i]
    return rList
           

if __name__ == "__main__":
    iList = randomList(10)
    print(iList)
    print(countingSort(iList))
    # print(timeit.timeit("selectionSort(iList)","from __main__ import selectionSort,iList",number = 1))
    
                 

总结

 从表格上来看,排序100次用时最少,速度最快的应该是快速排序。果然是名副其实。选择排序的速度与快速排序相差无几。用时最多、速度最慢的是插入排序,其次就是冒泡排序。当然,根据输入数列的不同,这个排名可能会有所变动。

参考

图解leetcode初级算法(python版)--胡松涛

图形化排序算法比较:快速排序插入排序选择排序冒泡排序

 图形化排序算法比较:快速排序、插入排序、选择排序、冒泡排序  查看详情

排序算法-冒泡排序(改),选择排序

上次说冒泡排序留下2个问题,一个是选择排序,一个是冒泡排序性能,这次会先说选择排序,然后说冒泡排序的优化一选择排序选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的元素中选出最小(或最大)的一个... 查看详情

冒泡排序算法与选择排序算法

1数组高级以及Arrays(掌握)2(1)排序3A:冒泡排序4相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处。同理,其他的元素就可以排好。56publicstaticvoidbubbleSort(int[]arr){7for(intx=0;x<arr.length-1;x++){8for(inty=0;y<arr.le... 查看详情

排序算法(冒泡排序,选择排序,插入排序,快速排序)

数组的排序算法选择排序每次选择所要排序得数组中的最大值(由大到小排序,由小到大排序则选择最小值)的数组元素,将这个数组元组的值与最前面没有排序的数组元素进行交换,第一次排序之后,最大的数字来到了第一位,再从第... 查看详情

排序算法:选择排序和冒泡排序(代码片段)

目录1.选择排序2.冒泡排序1.选择排序voidSelectSort(vector<int>&iv) intbegin=0; intend=iv.size()-1; while(begin<=end) intmaxi=begin; intmini=end; for(inti=begin;i<=end 查看详情

排序算法:选择排序和冒泡排序(代码片段)

目录1.选择排序2.冒泡排序1.选择排序voidSelectSort(vector<int>&iv) intbegin=0; intend=iv.size()-1; while(begin<=end) intmaxi=begin; intmini=end; for(inti=begin;i<=end;& 查看详情

排序算法(冒泡排序选择排序插入排序快速排序归并排序)(代码片段)

1、冒泡排序  (英语:BubbleSort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排... 查看详情

排序算法之一--冒泡排序,选择排序,插入排序

一.排序算法定义  1.排序算法定义    排序算法是一种能将一串数据依照特定顺序进行排列的一种算法  2.六种排序算法理解方式    想象小时候老师给我们按照身高进行排队时用到的方法,脑子里面要浮现老师排... 查看详情

算法小结-冒泡选择排序直接插入排序

1.冒泡排序法:比较相邻的两个元素,如果前边比后边大,就对调两元素,一趟下来,最大的数放在最右边,就像泡泡上升一样。代码:/**冒泡*/staticvoidbubble_sort(int[]array){for(inti=0;i<array.length;i++){for(intj=i;j<array.length;j++){if(array... 查看详情

算法排序lowb三人组冒泡排序选择排序插入排序

参考博客:基于python的七种经典排序算法  [经典排序算法][集锦]   经典排序算法及python实现首先明确,算法的实质是列表排序。具体就是操作的列表,将无序列表变成有序列表!一、排序的基本概念和分类 ... 查看详情

排序算法

...据结构》简单的把上面的算法总结一下:简单算法:冒泡排序,简单选择排序,直接插入排序改进算法:希尔排序,堆排序,归并排序,快速排序插入排序:直接插入排序和希尔排序交换排序:冒泡排序和快速排序选择排序:简... 查看详情

《数据结构与算法之美》08——排序冒泡排序插入排序选择排序

一、如何分析一个“排序算法”从三个维度进行评价和分析:1.排序算法的执行效率a.最好情况、最坏情况、平均情况时间复杂度b.时间复杂度的系统、常数、低阶c.比较次数和交换(或移动)次数 2.排序算法的内存消耗... 查看详情

算法_基本排序算法之冒泡排序,选择排序,插入排序和希尔排序

  排序的元素实现了Comparable接口,以达到对于通用性.  最基础的排序是冒泡排序,下面是其思路:比较相邻的元素。如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对... 查看详情

算法排序冒泡排序

上一篇给大家说了选择排序的原理,这一次我们来说一说冒泡排序的原理其实冒泡排序和选择排序一样都是很简单的排序方式。本文将介绍以下内容排序原理算法实现(JAVA)测试阶段算法分析排序原理每次循环都遍历一次数组... 查看详情

排序算法3种简单排序(选择,冒泡,插入)

  排序是数据处理中十分常见且核心的操作,虽说实际项目开发中很小几率会需要我们手动实现,毕竟每种语言的类库中都有n多种关于排序算法的实现。但是了解这些精妙的思想对我们还是大有裨益的。本文简单温习下最基... 查看详情

基本排序算法(冒泡排序选择排序插入排序快速排序归并排序基数排序希尔排序)

冒泡排序publicstaticvoidbubbleSort(int[]arr){intlgn=arr.length;for(inti=0;i<lgn-1;i++){for(intj=0;j<lgn-1-i;j++){if(arr[j]>arr[j+1]){inttemp=arr[j+1];arr[j+1]=arr[j];arr[j]=temp;}}}}选择排序publicsta 查看详情

常见的排序算法

插入排序直接插入排序,折半插入排序,2-路插入排序,希尔排序快速排序冒泡排序,快速排序(冒泡排序改进),选择排序简单选择排序,树形选择排序,堆排序归并排序基数排序 查看详情

算法笔记_008:选择排序和冒泡排序蛮力法

目录1问题描述2解决方案2.1选择排序原理简介2.2具体编码(选择排序)2.3冒泡排序原理简介 2.4具体编码(冒泡排序) 1问题描述给定一个可排序的n元素序列(例如,数字、字符和字符串),将它们按照非降序方式重新排... 查看详情