常用排序算法-面试-数据结构(不断更新)

排序

概述

  1. 以下所有代码可以找一个在线运行python的代码,直接运行
  2. 排序算法分内部排序与外部排序,内部排序是数据记录在内存中进行排序,外部排序为排序数较大而需访问外存。常见的内部排序算法有:冒泡排序选择排序插入排序希尔排序归并排序快速排序堆排序计数排序桶排序基数排序

快排

思路

思路一:

  1. 针对一系列需要排序的数字,每一次都确定其中一个元素的真正位置,左边都比这个数字小,右边都比这个数字大。

    不断迭代,确定出最后整体每个元素的最终位置。

  2. 需要两个游标,一个low 一个high,一般都是 不断确定第一个元素的位置

    初始化状态,low指向待排序第一个元素,high指向待排序最后一个元素。

    然后high往前移动,直到移动到比第一个元素即要确定位置的元素小的元素,此时把low元素指向的位置赋值为high指向的元素。

    再然后,high不动了,low往前移动,直到移动到元素比带确定位置元素大的元素,此时把high元素指向的位置赋值为low指向的元素。

    如此反复,直到high和low重合了,则第一次排序结束,即第一个需要确定最终位置的元素,它的位置找到了。

    最后,把左右子集,不断重复上述过程

代码

思路一:

  1. 快排的代码中,就两个点很重要。 第一个点就是low游标和high游标交换,互相赋值的过程 第二个点就是不断递归,在子集合中求解待排序元素的最终位置

  2. 第一版代码

    # python3版本
    def quickSort(needList,first,last):
    	if(first>last):
    		return
    	if first==last:
    		return needList
    	low=first        # 注意点一 low和high游标和一开始传入的first last要用不同变量,以便处理下面的递归调用
    	high=last
    	num1=needList[low]        # 注意点二   要把每次需要排的元素单独拿出来
    	while low<high:
    	    while needList[high]>num1 and low<high:     # 注意点三  移动 赋值 两个操作都要有 且这里也要写上low<high条件,否则会报错 这里和下面都试过写if的逻辑,结果不太好写
    	        high-=1
    	    needList[low]=needList[high]
    	    while needList[low]<=num1 and low<high:   # 注意点四  在low游标和high游标,得选择一方拥有等号,以处理待排序之中,含有相等元素
    	        low+=1
    	    needList[high]=needList[low]
    	needList[low]=num1
    	quickSort(needList,first,low-1)
    	quickSort(needList,high+1,last)  # 注意点六  两个递归,后半部分的递归开始要是High+1,这个跟你一开始选择的是排序哪一个元素有关,如果是排序第一个元素,那就是这样high+1
    	return needList
    
    print(quickSort([6,3,5],0,2))
    

时空复杂度和应用场景

  1. 思路一:

    使用场景:当初始序列无序的时候,越有序,该算法的性能相对越差,因为如果整个序列是有序的,那么本来可以每次少比一半的情况就没有了,会变成每次都要比全部元素,则性能就会差

    时空复杂度都是针对python代码来分析的:
    时空复杂度:

    最优情况:即每次确定的元素都恰巧平分需要排序的列表,此时的时间复杂度是 n l o g n nlogn nlogn,原因是这个时候递归处的执行次数是 l o g n logn logn,然后每次递归函数内部的最深层循环都是n,就是while循环那里。所以总的时间复杂度为 n l o g n nlogn nlogn

    最坏情况:即每次确定的元素都是在原位置没动,即原列表是有序的。此时的时间复杂度是 n 2 n^2 n2,原因是这个时候递归处的执行次数是n,然后每次递归函数内部的最深层循环都是n,就是while循环那里。所以总的时间复杂度为 n 2 n^2 n2

    平均情况: 涉及到较为复杂的推导,可以先记下。 n l o g n nlogn nlogn

    从实际运行效果上来:在最优情况下,总的运行次数是 n l o g n + n l o g n nlogn+nlogn nlogn+nlogn,但是最坏情况下,总的运行次数是 n 2 n^2 n2,所以存在最优和最差情况,不要只盯着第一层看,要看总的运行次数和时间

    空间复杂度:还是递归的地方占用了空间, 最 优 l o g n , 最 坏 n 最优logn,最坏n logn,n

冒泡

思路

  1. 思路一:

    1. 对于待排序元素,首先确定排序规则,是由大到小,还是由小到大,然后首先确定首元素还是尾元素

    2. 下面只介绍最优的算法,使用最少的比较次数,且假设按照从小到大的顺序,首先确定首元素

    3. 从后到前,每相邻两个元素相互比较,依次往前迭代,当后比前小的时候,就交换两者顺序

      此处,如果首先要确定是尾元素,那就从前到后,每相邻两个元素进行比较

    4. 按照上面那种方法,每次到最前面都是最小的,第一个优化点,就是已经排好序的元素不用再参与排序,只比较到前一个即可

    5. 第二个优化点,就是按照3中的方法,一旦某趟比较没有发生交换,说明整体都已经有序,就无需在进行后续比较

代码

  1. 思路一:

    1. 第一版代码

      # python递归模式
      def maoPaoSort(num:list,final:int)->list:
       if final<0 or len(num)==0:
           return
       if len(num)==1:
           return num
       changeNum=0
       for i in range(final):
           if num[i]>num[i+1]:
               tmp=num[i]
               num[i]=num[i+1]
               num[i+1]=tmp
               changeNum+=1
       if changeNum==0:   # 针对上面所说的第二个优化点
           return num
       else:
           maoPaoSort(num,final-1)
       return num
      
      maoPaoSort([6,3,5],2)
      
    2. 第二版代码

      # python的非递归模式  从前往后冒泡
      def maoPaoSort(num:list)->list:
       length=len(num)
       if length==0:
           return
       if length==1:
           return num
       i,changeNum=0,0
       while  length>1:
           while i<length-1:
               if num[i]>num[i+1]:
                   tmp=num[i]
                   num[i]=num[i+1]
                   num[i+1]=tmp
                   changeNum+=1
               else:
                   i+=1
           if changeNum==0:
               return num
           length-=1
       return num
      
      maoPaoSort([6,3,5])
      
      #python的非递归模式  从后往前冒泡
      
      def buddleSort(listExp):
       if not len(listExp):      # 注意点二  if not 0 是返回true的
           return
       for i in range(len(listExp)):
           j=len(listExp)-1
           changeNum=0        # 注意点一  用来记录每趟比较过程中,发生交换的次数  对应优化点二
           while j>i:
               if(listExp[j]<listExp[j-1]):
                   listExp[j],listExp[j-1]=listExp[j-1],listExp[j]
                   changeNum+=1
               j-=1
           if(changeNum==0):
               return listExp
      
      print(buddleSort([6,3,5]))
      

时空复杂度&应用场景

  1. 思路一:

    使用场景:1. 顺序存储 2.原表越有序,性能相对越好

    时间复杂度:

    1. 最 坏 o ( n 2 ) 最 好 o ( n ) 平 均 O ( n 2 ) 最坏 o(n^2) 最好 o(n) 平均O(n^2) o(n2)o(n)O(n2)

      1. 最坏在递归那个方法的推导:

        1. 每递归一次,需要执行的次数分别为n-1,n-2,…直到1 所以,时间复杂度是 [ ( n − 1 ) + 1 ] ∗ ( n − 1 ) 2 − − − − > O ( n 2 ) \frac{[(n-1)+1]*(n-1)}{2}---->O(n^2) 2[(n1)+1](n1)>O(n2)

    空间复杂度:

    1. 第一版:最好o(1) 最坏: o ( n ) o(n) o(n),就是走了递归,递归是要消耗堆栈的
    2. 第二版:O(1) 没有特定需要存储空间的东西
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值