算法图解/二分查找/简单查找/选择排序/递归算法/快速排序算法/

大 O 表示法

大 O 表示法在讨论运行时间时,log 指的都是 log2

大 O 表示法指出了算法有多快,让你能够比较操作数,它指出了算法运行时间的增速,而并非以秒为单位的速度。

大 O 表示法指出了最糟情况下的运行时间。

下面按从快到慢的顺序列出了经常会遇到的5种大O运行时间:

  • O(log n),也叫对数时间,这样的算法包括二分查找
  • O(n),也叫线性时间,这样的算法包括简单查找
  • O(n * log n),这样的算法包括快速排序 —— 一种速度较快的排序算法
  • O(n2),这样的算法包括选择排序 —— 一种速度较慢的排序算法
  • O(n!),这样的算法包括旅行商问题的解决方案 —— 一种非常慢的算法
  1. O(1)

时间复杂度,比如操作一步到位这是常数级别的时间复杂,即为 O(1)。

a = 100 / 2 + 101 * 10 + 5 
  1. O(logn)

如下操作,每次 n 会被除以 3,遍历次数等于 以 3 为底 log n 次。在大 O 标记体系中,以 3 为底和以 5 为底没有区别,所以统一标记为 O(logn)。

def f(n):
    while n > 0:
        print(n)
        n //= 3
  1. o(n)

线型复杂度也是很理想的情况,如下面的操作,每次遍历,n 减去 3,这样总共遍历(n-1)/3 + 1 次后算法终止,根据大 O 标记法,算法的时间复杂为 O(n)。

def f(n):
    while n > 0:
        print(n)
        n -= 3
  1. O(nlogn)

如下面所示的两层循环,复杂度便是 nlogn。外层循环的运行次数为 n,里层循环的运行次数为 logn 次,所以一共需要 nlogn 次。

def f(n):
    for i in range(n):
        for j in range(1,n,2):
            print(i*j)
  1. O(n^2)

O(n^2) 是多项式时间复杂度的代表,此类算法的时间复杂度已经难以划分到高效算法集合中,它只能是问题的有效解,而不是高效解。如下两层 for 循环,时间复杂度就是 O(n^2)。

def f(n):
    for i in range(n):
        for j in range(n):
            print(i*j)
  1. O(2^n)

时间复杂度为 O(2^n) 的算法是指数级增长的,此类复杂度下求解的问题往往都是难题,因为随着问题规模 n 的增长,指数级的增长速度是惊人的。

例如经典的旅行商问题,商人要去 n 个地方拜访,如何规划拜访顺序才能使得旅行距离最短。如果仅拜访肉眼可见的两三个地方时,我们还能穷举所有拜访的组合,进而找到最短路径。

但是当问题规模 n 变大时,目前所有的计算机资源总和都难以在有限的时间里计算出最优的最短路径,这类问题的时间复杂度都为指数级,属于 NP 难问题。

二分查找与简单查找

二分查找的输入必须为有序的元素列表,查找的时候每次获取中间的元素。

简单查找则是按照顺序从头至尾的查找每个元素。

一般而言,对于包含n个元素的列表,用二分查找最多需要 log2n 步,而简单查找最多需要n步。

二分查找算法代码如下:

def binary_search(arr, num):
    arr.sort()  # 对输入参数先进行排序
    print arr
    low = 0
    high = len(arr) - 1
    while low <= high:	# 通过下表缩小范围
        mid = (low + high)/2
        if arr[mid] < num:
            low = mid + 1
        elif arr[mid] > num:
            high = mid - 1
        elif arr[mid] == num:
            return mid
    else:
        return "Not Exists"

a = [10, 2, 8, 1, 3, 20, 15]
print binary_search(a, 10)
#打印值
[1, 2, 3, 8, 10, 15, 20]
4

选择排序

选择排序的思路大概分为两步:

  1. 对要排序的 N 个元素依次进行比较,返回要获取的最大值或者最小值;

  2. 将返回的最大值或者最小值添加到新的列表中,在原列表中删除该元素,并继续重复步骤 a,直到原列表中没有元素;

选择排序代码:

def find_min(arr):  # 找出最小值
    min_value = arr[0]
    index = 1
    while index <= len(arr) - 1:
        if arr[index] < min_value:
            min_value = arr[index]
        index += 1
    return min_value


def select_sort(arr):   # 将找到的最小值依次在原列表中删除,并存入新列表
    dst = []
    for i in range(len(arr)):
        min_value = find_min(arr)
        dst.append(min_value)
        arr.remove(min_value)
    return "dst is {0}".format(dst)

a = [10, 2, 8, 30, 3, 20, 15]
print select_sort(a)
# 输出
dst is [2, 3, 8, 10, 15, 20, 30]

递归算法

每个递归函数都分为两部分:基线条件和递归条件。

基线条件是指函数的终止条件,即避免形成死循环的部分;递归条件则指的是函数自己调用自己。

计算阶乘的递归函数

def fact(x):
    if x == 1:
        return 1
    else:
        return x * fact(x-1)

print fact(5)

计算斐波那契数列某一项的值

def fibo(n):
    if n == 0 or n == 1:
        return n
    else:
        return fibo(n-1) + fibo(n-2)

print fibo(7)

快速排序算法

快速排序比选择排序的算法快很多,它可借助递归方法实现,主要步骤如下:

  1. 选择基准值;

  2. 将待排序的数组分成两个子数组:小于基准值的元素和大于基准值的元素;

  3. 分别在对这两个子数组进行快速排序;

def quick_sort(array):
    if len(array) < 2:  # 为空或者只包含一个元素时
        return array
    else:
        base = array[0]     # 基准值
        less = [x for x in array[1:] if x <= base]      # 所有小于基准值的元素
        greater = [y for y in array[1:] if y > base]    # 所有大于基准值的元素
        return quick_sort(less) + [base] + quick_sort(greater)  # 对两组数据进行递归排序

a = [10, 2, 8, 30, 3, 20, 15]

print quick_sort(a)

散列表

散列表也被称为散列映射、映射、字典和关联数组等。在 python 语言中表现为字典形式,要求将同样的输入映射到相同的索引,将不同的输入映射到不同的索引。可将字典用于查找、服务器缓存等场景。

散列表的查找、插入和删除速度都非常快,散列表适合用于模拟映射关系以及用于防止重复。

广度优先搜素

从 A 到 B 地有很多种路径可以到达,但是只有一条路径是最短路径,这种寻找最短、最优路径问题被称为最短路径问题。

解决最短路径问题的算法被称为广度优先搜索。

图由节点和边组成,一个节点可能与众多节点直接相连,这些节点被称为邻居。

广度优先搜索是一种用于图的查找算法,可解决两类问题:

  1. 从节点A出发,有前往节点B的路径吗?

  2. 从节点A出发,前往节点B的哪条路径最短?

有向图与无向图的区别:

  • 有向图中的边为箭头,箭头的方向指定了关系的方向;

  • 无向图中的边不带箭头,其中的关系是双向的;

广度优先搜索的运行时间为O(人数 + 边数),这通常写作O(V + E),其中V为顶点(vertice)数,E为边数。

广度优先算法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值