Title

算法基础之冒泡排序,选择排序,插入排序,快排序

排序算法基础

一.算法衡量标准

问:现在有两个程序,这两个一样程序的运行时间如何衡量?前提是什么?

答:可以通过time模块来获取程序的运行时间进行比较,前提是必须在同硬件环境下(比如:CPU/内存)运行,才有意义

 

根据上面问题,我们单单使用时间差来衡量程序的快慢没有意义。因此,我们可以根据程序执行的大概次数来衡量程序的快慢。把这种衡量的方式称之为时间复杂度,通过它来用来评估算法运行效率,使用O()来表示

举例:

# 程序                                        # 时间复杂度
print('Hello World')                             O(1):表示执行一次

for i in range(n):  
   print('Hello World')                         O(n):表示循环执行n次
 
for i in range(n):  
   for j in range(n):        
       print('Hello World')                     O(n^2):表示循环执行n^2
           
for i in range(n):  
   for j in range(n):      
       for k in range(n):          
           print('Hello World')                 O(n^3):表示循环执行n^3

print('Hello World')
print('Hello Python')
print(‘Hello Algorithm’)                         O(1):表示执行一次,没有循环
   
   
for i in range(n):
   print('Hello World’)    
         for j in range(n):      
        print('Hello World')                 O(n^2):表示循环执行两次,有两个循环


while n > 1:                                     例:n = 64,则2^6 = 64 即今过6次循环减半
print(n)                                     程序结束,所以为O(log2^n),或者O(logn)           n = n // 2                
                             

总结:

  • 时间复杂度是用来估计算法运行时间的一个式子(单位)。

  • 一般来说,时间复杂度高的算法比复杂度低的算法慢。

  • 常见的时间复杂度(按效率排序)

O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^2logn)<O(n^3)

  • 不常见的时间复杂度(看看就好)

O(n!) O(2n) O(nn) …

  • 如何一眼判断时间复杂度?

    • 循环减半的过程O(logn)

    • 几次循环就是n的几次方的复杂度

了解:空间复杂度(占用内存空间大小,也是用O表示)

二.列表排序

将无序列表变为有序列表

应用场景:

各种榜单 各种表格 给二分排序用 给其他算法用

排序low B三人组:

  • 冒泡排序:列表每两个相邻的数,如果前边比后边的大,那么交换这两个数。

  • 选择排序:选择一个我认为的最小值的索引,然后不断的与列表中的其他数据进行比较,若该索引对应的 值大,则交换这两个数。

  • 插入排序:列表被分为有序区和无序区,有序区开始只有一个元素,开始排序时会将第二个元素与第一个

    元素(即有序区的初始元素)进行比较,并赋给一个变量,然后比较完根据大小进行顺序排

    列,依次往后,不断的将元素从无序区插到有序区内 。

  • 快速排序:选取一个元素P归位(一般第一个元素),归位指的是列表被分为两部分,左边的都比其小,

    右边的都比其大,然后依次往后递归,直到左边和右边都排序结束

排序NB二人组:

  • 堆排序

  • 归并排序

没什么人用的排序:

  • 基数排序

  • 希尔排序:

    一种分组插入排序算法,首先选取元素的个数n除以2获得一个整数d1,将所有元素分组,每组

    相邻元素之间距离为d1,然后在各组元素内直接进行插入排序,然后再取d1除以2获得d2,将

    所有元素分组每组元素相邻间距为d2,进行插入排序,直到d等于1,这是一个逐渐获得有序序列

    的方法,直到最后一趟获得真正有序的序列

  • 桶排序

  • 计数排序:建立一个列表li中最大元素+1的长度的都是0元素的列表count,如果原li列表中出现某个元

    素,就在这个元素对应的索引位(比如元素为3,就将索引为3的位置的0元素+1)加1,然后清

    空原列表li,将非0对应位置的索引添加进li中即可完成排序

三.冒泡排序

时间复杂度:O(n^2)

代码演示:

def bubble_sort(li):
   for i in range(len(li)-1):
   #     如果一次都没循环成功,说明排序是正确的,则直接跳出结束
       flag = True
       for j in range(len(li)-1-i):
           if li[j] > li[j+1]:
               li[j], li[j+1] = li[j+1], li[j]
               flag = False
       if flag:
           return
li = [9,8,7,6,5,4,3,2,1]

bubble_sort(li)
print(li)

四.选择排序

时间复杂度:O(n^2)

代码演示:

def select_sort(li):
for i in range(len(li)):
   # 假设最小值为i索引对应的值
  minloc = i
       for j in range(i+1,len(li)):
        if li[minloc] > li[j]:
               li[minloc],li[j] = li[j],li[minloc]
li = [9,8,7,6,5,4,3,2,1]

select_sort(li)
print(li)          

五.插入排序

时间复杂度:O(n^2)

代码演示:

def insert_sort(li):
for i in range(1,len(li)):
  tmp = li[i]
       j = i-1
  while j>=0 and li[j]>tmp:
      li[j+1] = li[j]
           j = j-1
       
  li[j+1] = tmp
   
li = [9,8,7,6,5,4,3,2,1]

select_sort(li)
print(li)  

六.快排序

时间复杂度:O(logn)

#归位函数
def partition(li, left, right):
# 设置最小索引值为tmp
tmp = li[left]
   while left<right:
  # 当右边元素比归位temp大时,一直往左走
  while left<right and li[right] >= tmp:
  right = right-1
       # 当右边某个元素比归位temp小时,该元素传到左边
  li[left] = li[right]
       # 此时当左边元素比归位temp小时,一直往右走
  while left < right and li[left]<=tmp:
  left = left+1
       # 当左边某个元素比归位temp大时,该元素传到右边
  li[right] = li[left]
   #全部循环走完,两边指针走到一起,该索引位就是归位的那个值
   li[left] = tmp
   # 然后将此索引返回出去
   return left
       


def quick_sort(li, left,right):  # left表示最小索引,right表示最大索引

if left < right:
       # 归位函数,返回值就是位置的索引,分开左右
       mid = partition(li, left, right)
       # 归位之后再递归
       quick_sort(li,left,mid-1)
       quick_sort(li,mid+1,right)

       
li = [8,3,4,5,7,6]
quick_sort(li,0,5)
print(li)

七.希尔排序

时间复杂度:O(1+τ)≈O(1.3n)

def shell_sort(li):
   gap = len(li) // 2
   while gap > 0
  for i in range(gap, len(li)):
           tmp = li(i)
           j = i - gap
           while j > =0 and tmp < li(j):
               li[j + gap] = li[j]
               j -= gap
           li[j + gap] = tmp
       gap /= 2
       
li = [9,8,7,6,5,4,3,2,1]

shell_sort(li)
print(li)

八.计数排序

时间复杂度:O(n)

def count_sort(li):
   # 列表生成式,生成一个最大元素+1的都是0的列表
   count = [0 for _ in range(45)]
   print(count)
   # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
   # 循环给定列表,指定元素所对应的索引位置,有值则加一
   for k in li:
       count[k] += 1
   print(count)
   # [0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
   # 清空原li列表
   li.clear()
   # 根据索引的顺序完成数据的添加,此时索引就是原列表的元素
   for k, v in enumerate(count):
       print(k,v)
       for i in range(v):
           li.append(k)
li = [11,3,44,33,22,4,5,32,42,3]
count_sort(li)

print(li)

 

九.列表查找

  • 顺序查找

    从列表的第一个元素开始,顺序进行搜索,直到找到为止

  • 二分查找

    有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值进行比较,可以使候选区减少一半

# 递归版二分查找
def bin_serch_rec(data_set,value,low,high):
   if low <= high:
       mid =(low + high )// 2
       if data_set[mid] == value:
      return mid
       elif data_set[mid]>value
      return bin_serch_rec(data_set,vlaue,low,mid-1)
       else:
           return bin_serch_rec(data_set,value,mid+1,high)
    else:
       return

 

 

 

posted @ 2020-04-02 23:52  Mr江  阅读(343)  评论(0编辑  收藏  举报