摘要-图解算法

本文是《图解算法》的摘要,涵盖了算法简介、选择排序、递归、快速排序、散列表、图相关算法(如广度优先搜索和狄克斯特拉算法)以及NP完全问题和动态规划。讨论了贪婪算法作为近似算法的适用性,强调了动态规划在解决优化问题中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《图解算法》摘要

平时知道优缺点,校招要懂算法实现;

算法简介

  • 二分查找
def binary_search(list, item):
    low = 0
    high = len(list) - 1
    while low < high:
        mid = (low + high) / 2
        guess = list[mid]
        if guess == item:
            return mid
        elif guess < item:
            low = mid + 1
        else:
            high = mid - 1
    return None
  • 大O表示法指出了算法的增速,即算法有多快,一些常见的大O运行时间:
    • O(log(n)) ,也叫对数时间,包括二分查找;
    • O(n) ,也叫线性时间,包括简单查找;
    • O(nlog(n)) ,包括快速排序;
    • O(n2) ,包括选择排序
    • O(n!) ,旅行商问题

选择排序

行为数组链表
读取 O(1) O(n)
插入 O(n) O(1)
删除 O(n) O(1)

* 数组用的很多,因为它支持随机访问;链表只能顺序访问

def selectionSort(alist):
    for i in range(len(alist)-1, 0, -1):
        maxone = 0
        for j in range(1, i+1):
            if alist[j] > alist[maxone]:
                maxone = j
        alist[maxone], alist[i] = alist[i], alist[maxone]
    return alist

递归

  • 每个递归函数都有两个部分:基线条件(base case)和递归条件(recursive case)。递归条件是函数调用自己,而基线条件势函数不再调用自己。
def countdown(i):
    print i
    if i <= 0:
        return
    else:
        countdown(i-1)
  • 栈:调用另一个函数时,当前函数暂停并处于未完成状态;

快速排序

def quick_sort(a):
    if len(a) < 2:
        return a
    target = a[0]
    small = [i for i in a[1:] if i <= target]
    large = [i for i in a[1:] if i > target]
    return quick_sort(small) + [target] + quick_sort(large)

散列表

  • 散列函数准确地指出了价格的存储位置,原因如下:
    • 散列函数总是将同样的输入映射到相同的索引;
    • 散列函数将不同的输入映射到不同的索引;
    • 散列函数知道数据有多大,只返回有效的索引;
  • 在你将学习的复杂数据结构中,散列表可能是最有用的,也被称为散列映射、映射、字典和关联数组;
  • 散列表的实例:DNS解析(DNS resolution),缓存;
  • 如果散列表存储的链表很长,散列表的速度将急剧下降。然而,如果使用的散列函数很好,这些链表就不会很长;
  • 在平均情况下,散列表的查找(获取给定索引处的值)速度和数组一样快,而插入和删除速度和链表一样快,因此它兼具两者的优点;
  • = ,一旦填装因子大于0.7,就调整散列表的长度,将数据增长一倍;

图相关

广度优先搜索

  • 广度优先搜索不仅查找从A到B的路径,而且找到的是最短路径;
  • 图用于模拟不同东西是如何相连的;
from collections import deque


def search(name, graph):
    # 创建一个队列
    search_queue = deque()
    search_queue += graph[name]
    searched = []
    while search_queue:
        person = search_queue.popleft()
        if person_is_seller(person):
            print(person, 'is a mango seller!')
            return True
        else:
            search_queue += graph[person]
    return False

def person_is_seller(name):
    return name[-1] == 'm'


def main():
    # 关系图
    graph = {}
    graph['you'] = ['alice', 'bob', 'claire']
    graph['bob'] = ['anuj', 'peggy']
    graph['alice'] = ['peggy']
    graph['claire'] = ['thom', 'jonny']
    graph['anuj'] = []
    graph['peggy'] = []
    graph['thom'] = []
    graph['jonny'] = []

    search('you', graph)


if __name__ == '__main__':
    main()
  • 如果任务A依赖于任务B,在列表中任务A就必须在任务B后面,这被称为拓扑排序;

狄克斯特拉算法

  • 要计算非加权图中的最短路径,可使用广度优先搜索。要计算加权图中的最短路径,可使用狄克斯特拉算法;
  • 狄克斯特拉算法只适用于有向无环图;
def main():
    # 有向无环图
    graph = {}
    graph['start'] = {}
    graph['start']['a'] = 6
    graph['start']['b'] = 2
    graph['a'] = {}
    graph['a']['fin'] = 1
    graph['b'] = {}
    graph['b']['a'] = 3
    graph['b']['fin'] = 5
    graph['fin'] = {}

    # 开销表
    infinity = float('inf')
    costs = {'a': 6, 'b': 2, 'fin': infinity}

    # 存储父节点
    parents = {'a': 'start', 'b': 'start', 'fin': None}

    # 记录处理过的节点
    processed = []

    node = find_lowest_cost_node(costs, processed)
    while node is not None:
        cost = costs[node]
        neighbers = graph[node]
        for n in neighbers.keys():
            new_cost = cost + neighbers[n]
            if costs[n] > new_cost:
                costs[n] = new_cost
                parents[n] = node
        processed.append(node)
        node = find_lowest_cost_node(costs, processed)

    print(graph)


def find_lowest_cost_node(costs, processed):
    lowest_cost = float('inf')
    lowest_cost_node = None
    for node in costs:
        cost = costs[node]
        if cost < lowest_cost and node not in processed:
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node


if __name__ == '__main__':
    main()

NP完全问题

贪婪算法(近似算法)

  • 贪婪算法可能不会获得最优解,但非常接近。在有些情况下,完美是优秀的敌人,有时候,你只需找到一个能够大致解决问题的算法即可。判断贪婪算法优劣的标准如下:
    • 速度有多快;
    • 得到的近似解与最优解的接近程度;
  • NP问题无处不在!如果能够判断出要解决的问题属于NP完全问题就好了,这样就不用去寻找完美的解决方案,而是使用近似算法即可
  • NP问题的规律:
    • 元素较少时算法的运行速度非常快,但随着元素数量的增加,速度变得非常慢;
    • 涉及“所有组合”的问题通常是NP完全问题;
    • 不能将问题分成小问题,必须考虑各种可能的情况。这可能是NP完全问题;
    • 如果问题涉及序列(如旅行商问题中的城市序列)且难以解决,它可能就是NP完全问题;
    • 如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题;
    • 如果问题可转换为集合覆盖问题或者旅行商问题,那它肯定是NP完全问题;
  • 小结:
    • 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解;
    • 对于NP完全问题,还没有找到快速解决方案;
    • 面临NP完全问题时,最佳的做法是使用近似算法;
    • 贪婪算法易于实现,运行速度快,是不错的近似算法;

动态规划

  • 动态规划的行的排列顺序无关紧要;
  • 小结:
    • 需要在给定约束条件下优化某种指标时,动态规划很有用;
    • 问题可分解为离散子问题时,可使用动态规划来解决;
    • 每种动态规划解决方案都涉及网格;
    • 单元格中的值通常就是你要优化的值;
    • 每个单元格都是一个子问题,因此你需要考虑如何将问题分解为子问题;
    • 没有放之四海皆准的动态规划解决方案公式;
      • 示例公式: cell[i][j]=Max(cell[i1][j],cell[i1][j])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值