Python中函数递归调用和算法排序之冒泡、选择、插入。

187 阅读7分钟

Python中函数递归调用和算法排序之冒泡、选择、插入。

函数递归

一、定义:

在Python中,递归调用是指函数在其定义中调用自身的过程。使用递归可以解决一些问题,使代码更加简洁和易于理解。在定义一个递归函数时,需要注意以下几点:

1. 基本情况:

定义递归函数时,必须包含一个或多个基本情况,即递归停止的条件。当递归函数达到基本情况时,不再调用自身,从而避免无限循环

2. 递归调用

在函数定义中调用自身,通常是带有不同参数的调用,以逐步向基本情况逼近。

二、典例:

1、下面我们来看一个经典的习题

> 斐波那契提出来了一个有趣的兔子尾问题:若一对成年兔子每月恰好生下一对小兔子(一雌一雄),在年初时,只有一对小兔子。在第一个月结束时,小兔子成长为成年兔子,到了第二个月结束时,这对成年兔子将生下一对小兔子。这种成长与繁殖的过程会一直持续下去,并假设生下的小兔子都不会死,那么一年之后共有多少对小兔子?

针对这个问题的思路:

  1. 第一个月:只有一对兔子
  2. 第二个月:还是一对,因为原来的兔子没长成
  3. 第三个月:原来兔子生了一对,现在有两对
  4. 第四个月:老兔子又生了一对新兔子,而上个月生的兔子还未长成,现在有3对
  5. 第五个月这时有两对兔子有生育能力,所以现在有5对
  6. 按照这个思路一直往下推...会发现一个规律:第n个月的兔子总数=第(n-1)个月的兔子总数+第(n-2)个月的兔子总数:n=(n1)+(n2) n=(n-1)+(n-2) 现在我们用python来解决这个问题:
def get_num(n):
    if n<=2:
        return 1
    else:
        return get_num(n-2)+get_num(n-1)
if __name__=="__main__":
    print(get_num(11))

2、函数递归实现n的阶乘问题

def get_number(n):
    if n<=1:
       return 1
    else:
        return n*get_number(n-1)
if __name__=="__main__":
    print(get_number(6))

算法

1.冒泡排序
概括:

冒泡排序(Bubble Sort)是一种简单但效率较低的排序算法。它的基本思想是多次遍历待排序的序列,比较相邻元素的大小,如果它们的顺序不符合要求就交换它们。通过多次遍历,将最大(或最小)的元素逐渐移动到序列的最后,从而实现排序。

步骤
  • 比较相邻的元素:从列表的第一个元素开始,比较它与下一个元素的大小
  • 交换位置:如果当前元素大于后一个元素则他没交换位置,后一个元素相对自己后一个元素比较大小如果小于后一个元素则不交换位置反之交换位置,然后按这个顺序依次比较直到最后一个元素。 冒泡排序2.jpg 综上可知,列表共有7个数字,一共排了6次。假如有10个数字,会排序几次呢,显然,答案是9次,也就是说,n个数排序n-1次。而每一轮的比较次数就不同了:每一轮结束后就会有一个数固定不参与比较了,也就是上一轮排的最后一个数。假设一个列表有n个数据元素参与比较,第一次比较次数n-1,第二次n-2,第三次n-3...依此类推得第i次为ni n-i直到最后一次发现有n-2个元素不参与比较,而不参与比较的元素都是从每轮开始加1。 所以,代码实现:
def get_sort():
    list1=[3,6,4,2,11,10,5]
    for i in range(0,len(list1)-1):
        for j in range(0,len(list1)-i-1):
            if list1[j]>list1[j+1]:
                temp=list1[j+1]
                list1[j+1]=list1[j]
                list1[j]=temp
    return list1
print(get_sort())
2.选择排序
概括

选择排序(Selection Sort)是一种简单直观的排序算法,它的基本思想是在未排序的部分中选择最小(或最大)的元素,然后将其放到已排序部分的末尾。该过程一直重复,直到所有元素都已经排序完成。

步骤
  1. 第一次排序就假定第一个数字为最小值
  2. 并让这数字与后面的数字作比较若找到比它小的就交换位置否则就不交换位置,并进入下一次排序。
  3. 依次用这种思想继续下去: 选择排序.png 综上可知排序的次数也是n1n-1次,参与比较次数也是nin-i个(这里的i是比较次数而不是图中的索引i)

代码实现:

def get_sort():
    list1 = [20, 40, 30, 10, 60, 50]
    for i in range(0, len(list1) - 1):
        positionMin = i
        for j in range(i + 1, len(list1)): #i+1指不需要再遍历当前假定的元素了
            if list1[j] < list1[positionMin]:
                positionMin = j
        list1[i], list1[positionMin] = list1[positionMin], list1[i]
    return list1
print(get_sort())
3.插入排序
概括

插入排序(Insertion Sort)是一种简单且直观的排序算法,它的基本思想是通过构建有序序列,对于未排序的数据,在已排序部分找到合适的位置插入。插入排序的过程可以类比为打扑克牌时的排序,将一张牌插入到已经有序的牌序中。

步骤
  1. 首先将数据列分为两个序列一个有序一个无序选择一个有序序列,这里我们以数据列的第一个值为有序序列。
  2. 第一次排序是将有序列的值与无序列的第一个值作比较,若小于则位置不变并且该无序列的的值将加入进有序列中形成一个新的有序列,反之位置交换还是形成一个新的有序列。
  3. 依旧继续这个思想往下走: 插入排序.png 综上可知:我们依旧是要遍历n-1次(即排序)但是现在每一轮排序次数要比较的次数则是取决于有序列表的元素个数。 代码实现:
list1=[4,6,8,5,9]
for i in range(1,len(list1)):
    key=list1[i] #定义无序列表的第一个值
    j=i-1 #定义有序列表的值
    while j>=0 and list1[j]>key:
        list1[j+1]=list1[j] #交换位置
        j-=1 #每比较一次j的值少一次
    list1[j+1]=key
print(list1)

总结:

综上可知冒泡排序比较的次数是最多的,效率最低,但是易于理解,优先级低于选择排序和插入排序。而选择排序则是有些不稳定的,当遇到相同大小的数据还是会比较甚至交换位置,适用于小规模数据排序。插入排序,排序稳定,对小规模数据排序或者部分有序数据排序较好。但是以上三种排序他们的时间复杂度都是O(n2)O(n^2),都不适用大规模数据排序。

附赠(二分查找)

思路:将数列平均分成2段将目标元素依次与中间值比较若大于它则在它右边然后接着分段直到不能分段,若小于它则在它右边,操作同上,若等于直接输出(注意:二分查找针对的是有序数列时间复杂度为O(logn)O(logn))。 代码实现:

def get_number(lis,num):
    left=0
    right=len(lis)-1
    while left<=right:
        mid=(left+right) // 2
        if lis[mid]==num:
            return f'目标值{num}的位置为{mid}'
        elif num<lis[mid]:
            right=mid-1
        else:
            left=mid+1
    return f'没有目标值'

target_value=6
list1=[1,2,3,4,5,6,7,8,9]
print(get_number(list1, target_value))

**最后,希望大家能学到东西,如果有不会的可在评论区留言哦,博主看到会第一时间为您解答的!**若想了解时间复杂度是什么可以等博主更新,若等不了的话博主也给你们找到了一篇较好的文章 [算法的时间复杂度(python版容易理解)+常用的时间复杂度、python代码--数据结构_python中执行次数t(n/2)怎么转换成时间复杂度-CSDN博客]