0
点赞
收藏
分享

微信扫一扫

python-数据结构与算法学习-查找排序

罗子僧 2022-01-25 阅读 90

一、时间复杂度和空间复杂度

(一)时间复杂度

  • 之前学过很多次,但都搞的不是很清楚
  • 时间复杂度:用来评估算法运行效率的一个式子,也就是评估算法相对运行时间,不同的代码时间复杂度不同,如简单的输入一行代码是O(1),一层for循环是O(n),三层for循环是n的三次方
    时间复杂度
    在这里插入图片描述

但这时可能有人问如果输入三行是不是就是3,其实不是这样的

在这里插入图片描述

  • 因为在计算机的高速运行状态下,我们的时间复杂度是一个大概的量级,向O(3)就约等于O(1),而n2+n就约等于n2
    在这里插入图片描述
  • 有时候我们会遇到题目让我们判断算法复杂度,这时我们有可以根据情况进行判断在这里插入图片描述

(二)空间复杂度

空间复杂度和时间复杂度主要思维相似,用来评估算法对内存占用的大小
一般在算法中习惯用“空间换时间”
在这里插入图片描述

二、查找算法

  • 这次主要学了顺序查找和二分查找
    在这里插入图片描述

(一)顺序查找

  • 顺序查找也叫线性查找,从列表第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表的最后一个元素为止,就是暴力查找,一个一个查,知道查到或者查完了也没有就截止
  • 附代码
    在这里插入图片描述

(二)二分查找

  • 二分查找就是利用排序好的列表,从中间进行分割,取low和high以及中间值mid,每次将查找数据和中间值相对比,如果小于中间值就说明查找的值就在前半段,也就是low和mid中间,如果大于同理在后半段,然后不断的取中间值不断的比较,当mid=查找的元素或者列表走完的时候,查找结束。
  • 附代码
def binary_search(li,val):
    left=0 
    right=len(li)-1
    while left<=right:
        mid=(right+left)//2
        if li[mid]==val:
            return mid
        elif li[mid]<=val:
            left=mid+1
        elif li[mid]>=val:
            right=mid-1
    else:
        return None

三、排序

  • 本次主要讲6种排序,分别是三种相对较慢的排序:冒泡排序,选择排序,插入排序。
  • 三种相对较快的排序:快速排序,堆排序,归并排序
    在这里插入图片描述

(一)冒泡排序

  • 冒泡排序就是从列表第一个数开始,将每两个相邻的数进行对比,如果前面比后面大,就交换这两个数,每当一趟排序后,最大的数就到了最后面,也就是有序区,无序区就减少一个数,再对无序区进行排序,遍历直到全部有序
  • 附代码
def bubble_sort(li):
    for i in (len(li)-1):
        exchange=False
        for j in len(li)-1-i:
            if li[j]>li[j+1]:
                li[j],li[j+1]=li[j+1],li[j]
                exchange=True
     if not exchange:
         return

(二)选择排序

  • 选择排序的思想就是首先遍历一遍列表,找出最小值和第一个值交换,然后在从第二个值开始查找最小值,放到第二个数,一直遍历到最后,即可排序完成
  • 附代码
def select_sort(li):
    for i in range(len(li)-1):
        min_d=i
        for j in range(i+1,len(li)):
            if li[j]<li[min_d]:
                min_d=j
        if min_d!=i: 
            li[j],li[min_d]=li[min_d],li[j]
        print(li)

(三)插入排序

  • 首先从列表中选一个数拿出来,然后从列表中在拿一个数和第一个数比较,小于放到左边,大于放到右边,然后不断遍历到最后,后面的数从后往前比较,当大于的时候就停止,不断遍历,完成排序
  • 附代码
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-=1
        li[j+1]=tmp
        print(li)

在这里插入图片描述

(四)快速排序

  • 快速排序相对复杂,其思想在于将列表不断拆分,然后归位一个元素,使该元素左边都小于它,右边都大于它,然后利用递归完成排序
    在这里插入图片描述
  • 所以快速排序代码分为两个部分,一个部分用于递归,一个部分用于元素归位
  • 归位代码
def quarrtion(li,left,right):
    tmp=li[left]
    while left<right:
        while left<right and li[right]>=tmp:
            right-=1
        li[left]=li[right]
        while left<right and li[left]<=tmp:
            left+=1
        li[right]=li[left]
        print(li)
    li[left]=tmp
    return left
  • 递归代码
def quick_sort(li,left,right):
    while left<right:
        mid=quarrtion(li,left,right)
        quick_sort(li,left,mid-1)
        quick_sort(li,mid+1,right)
  • 快速排序之所以叫快速排序,在于其时间复杂度小为O(nlogn)
    如图每一层都是n,有logn层,故时间复杂度为O(nlogn)
    在这里插入图片描述
  • 而上面三个排序的时间复杂度均为O(n*2)
  • 当n的数量级很大时,快速排序会比以上三种快很多
  • 下面要讲的堆排序和归并排序时间复杂度也为O(nlogn)

(五)堆排序

  • 堆排序相对复杂,利用树的原理进行排序,这里有几个概念要了解一下
  • 堆是一种特殊的完全二叉树结构,分为以下两种堆情况
    在这里插入图片描述
    堆排序分为以下几个过程
    在这里插入图片描述
  • 其实就是先挨个出数,每出一个数将最后一个元素放到顶部,然后还原成堆,直到所有的数都出去,即可完成堆排序
  • 所以我们的堆排序就是分为两个部分,一个是构造堆,一个是挨个出数
def sift(li,low,high):#构造堆的函数部分
    #param li:列表
    #param low:
    #param high:堆的最后一个元素的位置
    i=low# i最开始指向根节点
    j=i*2+1#j开始是左孩子
    tmp=li[low]#把堆顶存起来
    while j<=high:#只要j位置有数
        if j+1<=high and li[j+1]>li[j]:
            j=j+1#j指向右孩子
        if li[j]>tmp:
            li[i]=li[j]
            i=j
            j=2*i+1
        else:
            li[i]=tmp
            break
    else:
        li[i]=tmp#把tmp放到叶子节点上
def heap_sort(li):#堆排序的函数部分
    n=len(li)
    for i in range((n-2)//2,-1,-1):
        # i表示建堆的时候调整的部分的根的下标
        sift(li,i,n-1)
    #建堆完成了
    for i in range(n-1,-1,-1):
        #i指向当前堆的最后一个元素 
        li[0],li[i]=li[i],li[0]
        sift(li,0,i-1)#i-1是新的high
  • sift函数时间复杂度为logn
  • heap_sort时间复杂度为n
  • 故堆排序时间复杂度也为O(nlogn)
    堆排序代码非常复杂,在python中也有相应的模块
    在这里插入图片描述
    在这里插入图片描述

(六)归并排序

  • 归并排序分为两个部分,分别是归并merge,和排序
  • 运用递归的思想,将列表分解
    在这里插入图片描述
    如图
    在这里插入图片描述
    首先是merge(一次归并)部分
def merge(li,low,mid,high):
    i=low
    j=mid+1
    ltmp=[]
    while i<=mid and j<=high:#只要左右两边都有数
        if li[i]<li[j]:
            ltmp.append(li[i])
            i+=1
        else:
            ltmp.append(li[j])
            j+=1
        #while执行完,肯定有一部分没有数了
    while i<=mid:
        ltmp.append(li[i])
        i+=1
    while j<=high:
        ltmp.append(li[j])
        j+=1
    li[low:high+1]=ltmp#将ltmp写回li
  • 再是递归归并的部分
def merge_sort(li,low,high):
    if low<high:#至少有两个元素才进行归并
        mid=(low+high)//2
        merge_sort(li,low,mid)#排序好左边
        merge_sort(li,mid+1,high)#排序好右边
        merge(li,low,mid,high)#排序

*归并排序的时间复杂度也为O(nlogn)

七、排序总结

三种较快的排序对比
在这里插入图片描述
六种排序总结
在这里插入图片描述
本次学习就到这里,寒假加油!

举报

相关推荐

0 条评论