数据结构之几种常见的排序算法(一)——冒泡、选择、插入、快排、归并

  1. 冒泡排序
def bubble_sort(alist):
    n = len(alist)
    for i in range(0, n-1):
        for j in range(i+1, n):
            if alist[j] < alist[i]:
                alist[i], alist[j] = alist[j], alist[i]
    return alist

上述程序是从小到大排序。可以简单理解为,对于一个list来说,i是左边那个数的下标,j是右面那个数的下标。对于冒泡排序,就是用i右边的所有数(j)跟i对应的这个数进行比较。假如是从小到大排序,那么当后面那个数(j)比i对应的数小时,两个数交换,重复进行直到最后一个数。然后i+1,执行下一组循环。

  1. 选择排序
def select_sort(arr):
    n = len(arr)
    for j in range(0, n-1):
        min_index = j
        for i in range(j+1, n):
            if arr[i] < arr[min_index]:
                min_index = i
        arr[min_index], arr[j] = arr[j], arr[min_index]
    return arr

上述程序是从小到大排序。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。举例来说,以列表中第0索引值对应的数为最小值为例(arr[0]最小,min_index=0),将从1到最后索引值对应的数与arr[0]比较,若比arr[0]小,将当前索引值记为最小值对应的索引值(改变min_index),并继续比较。该层循环结束后将arr[0]与arr[min_index]交换,此时第0索引值对应的数为当前List中最小的数,再将列表中第1索引值对应的数做为最小值(arr[1]最小,min_index=1),以此类推。

  1. 插入排序
    '''
    插入排序可以考虑为打扑克牌时的排序
    '''
    def insert_sort(li):
        n=len(li) #待排序的数组长度
        for i in range(1, n): #从排序数组中的第二个数开始执行
            tmp = li[i] # 选择一张牌
            j=i-1 #这张牌前面一个的下标
            while j>=0 and li[j]>tmp:  # 牌前面的数是否否比较完 and 牌前面的数比这张牌大情况下才移动
                li[j+1]=li[j] # 牌前面的数依次向后移动
                j-=1 # 往前找一张牌
            li[j+1]=tmp # 牌前面的都遍历完了或者到达停止条件,将牌放置在对应位置上
        return li

插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

  1. 快速排序(重要)
    def quick_sort(li, left, right):
        if left < right:
            mid = middle_choose(li,left,right)
            self.quick_sort(li, left, mid-1)
            self.quick_sort(li, mid+1, right)
        return li

    def middle_choose(li,left,right):
        tmp = li[left]
        while left<right:
            while left<right and tmp<=li[right]:
                right-=1
            li[left]=li[right]
            while left<right and tmp>=li[left]:
                left+=1
            li[right]=li[left]
        li[left]=tmp
        return left

快速排序的基本思想是首先将序列的第一个数找到其在序列中的对应位置,即左边的数都比这个数小,右边的数都比这个数大。再对该数左边和右边分别执行相同操作(递归思想)。

  1. 归并排序
def merge(lst,low,mid,high):
    li1=lst[low:mid+1] # low~mid
    li2=lst[mid+1:high+1] # mid+1~high
    n1=len(li1)
    n2=len(li2)
    i, j=0, 0
    li=[]
    while i<n1 and j<n2:
        while i<n1 and j<n2 and li1[i]>li2[j]:
            li.append(li2[j])
            j+=1
        while i<n1 and j<n2 and li1[i]<li2[j]:
            li.append(li1[i])
            i+=1
    while i<n1:
        li.append(li1[i])
        i+=1
    while j<n2:
        li.append(li2[j])
        j+=1
    for k in range(low, high+1):
        lst[k]=li[k-low]


def merge_sort(li,start,end):
    if start<end:
        mid=(start+end)//2
        merge_sort(li,start,mid)
        merge_sort(li,mid+1,end)
        merge(li,start,mid,end)

归并排序的思想主要是从两个有序序列合并成一个有序序列而来(上面的merge()函数)。所以归并排序主要分为两个步骤,第一步是将给定序列递归二分,再将二分后的序列递归合并成一个有序序列。整个过程比较复杂,主要采用递归的思想。

上述五种排序是比较基本的排序方法,面试也经常会考到手撕代码,建议熟练掌握。附上上述五种排序的时间复杂度及稳定性:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值