算法--一揽子排序算法(1)

冒泡排序

  • 持续比较相邻的元素,使前者大于后者
  • 第i次排序后,最后的i个数字是有序的,因此内循环有(1,len(lis) - i)
  • 复杂度是n+(n-1)+(n-2)+…+1 = O(n^2)
def BubbleSort(lis):
    for i in range(len(lis)):
        print(lis)
        for j in range(1,len(lis)-i):
            if lis[j-1] > lis[j]:
                lis[j-1],lis[j] = lis[j],lis[j-1]
"""
[5, 4, 2, 1, 6, 3]
[4, 2, 1, 5, 3, 6]
[2, 1, 4, 3, 5, 6]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
"""

选择排序

  • 第i次选择列表中的第i大的元素与列表倒数第i个元素交换位置
  • 也可以交换最小的元素,读者可以试着改写一下
  • 复杂度和冒泡排序一样,但交换次数只有n次
def SelectSort(lis):
    for i in reversed(range(len(lis))):
        print(lis)
        max_index = i
        for j in range(i):
            if lis[j] > lis[max_index]:
                max_index = j
        lis[max_index],lis[i] = lis[i],lis[max_index]
"""
[5, 4, 2, 1, 6, 3]
[5, 4, 2, 1, 3, 6]
[3, 4, 2, 1, 5, 6]
[3, 1, 2, 4, 5, 6]
[2, 1, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
"""

插入排序

  • 经过第i次排序,前i+1个数字是有序的
  • 在第i次排序时,将第i+1个元素插入前i个有序列表中
  • 插入数字时,本算法采用腾位置的方式,也能一路换过去
  • 复杂度同上,O(n^2)
def InsertionSort(lis):
    for i in range(1,len(lis)):
        item = lis[i]
        j = i - 1
        while j >= 0 and lis[j] > item:
            lis[j+1] = lis[j]
            j = j - 1
        lis[j+1] = item
        print(lis)
"""
[4, 5, 2, 1, 7, 6, 3]
[2, 4, 5, 1, 7, 6, 3]
[1, 2, 4, 5, 7, 6, 3]
[1, 2, 4, 5, 7, 6, 3]
[1, 2, 4, 5, 6, 7, 3]
[1, 2, 3, 4, 5, 6, 7]
"""

希尔排序

  • 改自《算法-第四版》
  • 性能啥的不清楚
def ShellSort(lis):
    h,N = 1,len(lis)
    while h < N/3 :
        h = 3*h + 1 #1,4,13,40...
    while h>= 1:
        for i in range(h,N):
            j = i
            while j >= h and lis[j] < lis[j-h]:
                lis[j],lis[j-h] = lis[j-h],lis[j]
                j -= h
        print(lis)
        h = h // 3
"""
[5, 4, 8, 2, 1, 7, 6, 3] //原列表
[1, 4, 6, 2, 5, 7, 8, 3]
[1, 2, 3, 4, 5, 6, 7, 8]
"""

[1, 4, 6, 2, 5, 7, 8, 3]为4有序,即1,5||4,7||6,8||2,3这些中间间隔三位的数字都是有序的。然后h//3=>1变为1有序,可以大大减少选择排序比较的次数。


归并算法

  • 自底而上的分治算法
  • 分析截图自《算法设计与分析基础》
    这里写图片描述
class MergeSort:
  def mergeSort(self,lis):
    if len(lis) <= 1:
      return lis
    mid = len(lis) // 2
    left = self.mergeSort(lis[:mid])
    right = self.mergeSort(lis[mid:])
    print("left:{0},right:{1}".format(left,right))
    return self.__mergeToList(left,right)

  def __mergeToList(self,left,right):
    lis = []
    l,r = 0,0
    while l < len(left) and r < len(right):
      if left[l] < right[r]:
        lis.append(left[l])
        l += 1
      else:
        lis.append(right[r])
        r += 1
    lis += left[l:]
    lis += right[r:]
    return lis
"""
[5, 4, 8, 2, 1, 7, 6, 3]

left:[5],right:[4]
left:[8],right:[2]
left:[4, 5],right:[2, 8]
left:[1],right:[7]
left:[6],right:[3]
left:[1, 7],right:[3, 6]
left:[2, 4, 5, 8],right:[1, 3, 6, 7]

[1, 2, 3, 4, 5, 6, 7, 8]
"""

快速排序

  • 选取列表第一个元素为划分点
  • 从列表左边开始选取一个比划分点大的数字,从列表右边选取一个比划分点小的数字,然后交换,再重复。直到左索引到达右索引的位置,然后把划分点放到正确的位置。
  • 然后递归排序划分点左右的子列表
  • 最坏情况:如果列表已经有序,那么快速排序的右索引会傻傻地白扫一遍又一遍,最后的复杂度会是O(n^2)
class QuickSort():
  def sort(self,lis):
    self.__sort(lis,0,len(lis)-1)

  def __sort(self,lis,start,end):
    if end <= start:
      return
    j = self.__partition(lis,start,end)
    self.__sort(lis,start,j-1)
    self.__sort(lis,j+1,end)

  def __partition(self,lis,start,end):
    i,j = start+1,end
    pivot = lis[start]
    while True: #这个循环找出(左>pivot)和(右<pivot)的元素并交换
      while lis[i] < pivot:
        if i == end:
          break
        i += 1
      while lis[j] > pivot:
        if j == start:
          break
        j -= 1
      if i>=j:
        break
      lis[i],lis[j] = lis[j],lis[i]
    lis[start],lis[j] = lis[j],lis[start]#把哨兵放到正确的位置
    return j
三向划分的改进版本->用于有大量重复元素
class Quick3way:
  def sort(self,lis):
    self.__sort(lis,0,len(lis)-1)

  def __sort(self,lis,start,end):
    if end <= start:
      return
    lt,i,gt = start,start+1,end
    pivot = lis[start]
    while i <= gt:
      if lis[i] < pivot:
        lis[lt],lis[i] = lis[i],lis[lt]
        i += 1
        lt += 1
      elif lis[i] > pivot:
        lis[i],lis[gt] = lis[gt],lis[i]
        gt -= 1
      else:
        i += 1
    self.__sort(lis,start,lt-1)
    self.__sort(lis,gt+1,end)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值