算法基础笔记:查找、排序

138 阅读2分钟

1. 递归

递归的特点: 调用自身 结束条件

递归的例子:汉诺塔问题

图片.png

图片.png 2的64次方

    if n > 0:
        hanoi(n-1,a,c,b)
        print("moving from %s to %s" %(a,c))
        hanoi(n-1,b,a,c)


hanoi(6,'A','B','C')

图片.png

2.时间复杂度

定义:用来评估算法运行效率的一个式子

图片.png

3.查找

顺序查找 linear Search 时间复杂度O(n)

思路:

  • 输入:列表、待查找元素
  • 输出:元素下标 (未找到元素时一般返回none或-1
    for ind, v in enumerate(li):
        if v == val:
            return ind
        else:
            return None 

li = [1, 2, 3]
print(linear_search(li, 3))

二分查找 binary_search 时间复杂度log(n)

    left = 0
    right = len(li) - 1
    while left <= right:  # 候选区有值
        mid = (left + right) // 2
        if li[mid] == val:
            return mid
        elif li[mid] > val:
            right = mid - 1
        else:
            left = mid + 1
    else:
        return None

li = [1, 2, 31, 4, 5, 3]
res = binary_search(li, 3)
print(res)

4.排序

冒泡排序 时间复杂度 O(n²)

思路:

  • 列表每两个相邻的数,如果前面比后面大,则交互这两个数
  • 一趟排序完成后,则无序区减少一个数,有序区增加一个数
  • 一共运行列表长度-1次
    for i in range(len(li)-1):  # n-1趟(最后一个没有比的了),第i趟,从0开始
        exchange = False
        for j in range(len(li)-i-1): # 箭头从0开始,到n-i-1,逐个向上
            if li[j]>li[j+1]:  # 升序> 降序<
                li[j],li[j+1] = li[j+1],li[j]
                exchange = True
        print(li)
        if not exchange:
            return

# 生成随机数
# import random
# li= [random.randint(0,10) for i in range(10)]
# print(li)
li = [1,2,3,4,5,6]
bubble_sort(li)

选择排序 select sort 时间复杂度:o(n²)

思路:

  • 一趟排序记录最小的数,放到第一个位置
  • 再一趟排序记录列表无序区最小的数,放到第二个位置
  • 算法关键点:有序区无序区 无序区最小的位置
    for i in range(0,len(li)-1):
        min_loc = i  # 先假定无序区第一个最小
        for j in range(i+1,len(li)):  # 无序区找最小,比如从第二个到最后,
            if li[j] < li[min_loc]:
                min_loc = j # 假定第5位最小
        li[i],li[min_loc] = li[min_loc],li[i]  # 第2位和第5位交换顺序
        print(li) # 运行结束打印列表


li = [3,5,1,2,7,8]
res = select_sort(li)
print(li)

插入排序 insert sort 时间复杂度 O(n²)

思路:

  • 初始时手里(有序区)只有一张牌
  • 每次(从无序区)摸一张牌,插入到手里已有牌的正确位置

def insert_sort(li):
    # 比如手里有一张牌了,摸到第二张牌,i=1,j
    for i in range(1,len(li)): # i表示摸到的牌下标,不算第一张牌
        tmp = li[i]  #摸到的牌
        j = i-1 # j表示手里的牌

        while j >=0 and li[j] > tmp :
            li[j+1] = li[j] # 把j往右移
            j -=1 # 往左移
        li[j+1] = tmp #
        print(li)

li = [1,3,1,2,4,5,6,7]
print(li)
insert_sort(li)

快速排序 时间复杂度 :O(nlogn)

思路:

  • 取一个元素P(可以是第一个元素),使元素P归位;
  • 列表被P分成两部分,左边都比P小,右边都比P大;
  • 递归完成排序;

图片.png

快速排序思路: 可以理解为取出第一个元素5, 从右边第一个找比5小的则放入左边的第一个位置, 然后从左边找比5大的放入右边第一个,依次类推。

def partition(li, left, right):  # li表示列表,left,right表示左右边界
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:  # 从右面开始找比tmp小的数
            right -= 1  # 往左继续移动
        li[left] = li[right]  # 找到了,右边的值放到左边的空位上,此时右边出现一个空位
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]  # 把左边的值写到右边的空位上
    li[left] = tmp  # 把tmp归位
    return left


def quick_sort(li, left, right):
    if left < right:  # 至少右两个元素
        mid = partition(li, left, right)
        #分开操作
        quick_sort(li, left, mid - 1)
        quick_sort(li, mid + 1, right)


li = [5, 7, 4, 6, 3, 1, 2, 9, 8]
quick_sort(li,0, len(li) - 1)
print(li)

快排的问题

  • 涉及递归