《算法图解》知识点纪要

《算法图解》,Aditya Bhargava 著,袁国忠 译,人民邮电出版社
本书的目的就是要把难懂的技术主题说清楚,让这本算法书易于理解(摘自作者前言)

读后感

《算法图解》是经典的算法书,受到很多人推崇为入门书籍,第一次阅读此书是20年上半年,觉得内容比较浅显,粗略看过,第二次是21年上半年,对于例子部分跳过较多,原理部分详细阅读,并仔细做了纪要

此书作为算法入门书籍的优势在于讲解生动,但是由于算法这个话题太过于广泛,所以阅读起来会觉得书本逻辑跳跃较大,前后章节的关联性时有时无,下面尝试理一理书本的内容逻辑

  • 数据结构:数组、链表、散列表、队列、调用栈、二叉查找树
  • 算法思想:二分查找、递归算法、分治算法、动态规划、贪婪算法、广度优先算法
  • 排序算法:选择排序、快速排序
  • 经典算法:迪杰斯特拉算法、K最近邻算法
  • 拓展内容:MapReduce、反向索引、傅里叶变换、并行算法、线性规划、加密算法等

以下是知识点纪要,部分代码转化为C++给出


1 二分查找

  • 有序列表
  • 对数时间
  • 大O表示法是最坏情况下的运行时间
  • 算法的速度指的是操作数的增速,不以秒为单位
  • 旅行商问题的时间复杂度是O(n!)
int binary_search(vector<int>& nums, int item){
    int lhs = 0, rhs = nums.size()-1;
    while(lhs <= rhs){
        int mid = lhs + (rhs - lhs) / 2;
        // 猜数字
        int guess = nums[mid];
        if (guess == item){
            return mid;
        } 
        else if (guess > item){
            rhs = mid - 1;
        }
        else{
            lhs = mid + 1
        }
    }
    // 数字没找到
    return -1;
}

2 选择排序

  • 计算机内存均有各自的地址,用于存放数据
  • 数组和链表
    数组和链表是两种基本的数据结构。
    (1)数组是提前申请内存,内存大小是固定的,元素都在一起,优点是便于随机读取,缺点是难以确定合适的内存
    (2)链表的每个元素不仅储存值,还储存下一个元素的地址,元素是分开的,优点是便于插入和删除元素,缺点是无法随机读取
  • 选择排序的时间复杂度是O(n^2),每轮循环需要找寻最小数

3 递归

  • 递归便于理解,但不提高效率
    递归的基本做法就是函数调用自己
    如果使用循环,程序的性能可能更高,如果使用递归,程序可能更容易理解
    递归函数包含基线条件(base case)和递归条件(recursive case),前者是终止条件,避免无限循环,后者是函数调用自己
void countdown(int i){
    cout << i << endl;
    // base case
    if (i <= 0){
        return;
    }
    // recursive case
    else{
        countdown(i-1);
    }
}
  • 调用栈(call stack)
    基本操作是压入和弹出
    思想是后进先出(Last In First Out,LIFO)
    递归函数也使用调用栈:递归分解问题是自上而下,分解过程的中间量入栈中,求解问题的时候自下而上,出栈进行依次计算
    使用栈的代价是消耗内存

4 快速排序

  • 分治思想
    分而治之(divide and conquer,D&C),一种著名的递归方法
    分治包含两个步骤,找出可以便捷处理的基线条件,不断分解问题直至符合基线条件
  • 快速排序
    快速排序也是一种分治算法
    快速排序的步骤是:(1)设定基准(2)将余下的元素分成小于等于基准和大于基准的两个分区(3)对分区重复(1)和(2),直至分区不多于一个数为止
    快排的平均时间复杂度是O(nlogn),其算法速度与基准取值有关
def quicksort(array):
    if len(array) < 2:
        return array
    else:
        pivot = array[0]
        # 小于基准的子数组
        less = [i for i in array[1:] if i <= pivot]
        # 大于基准的子数组
        greater = [i for i in array[1:] if i > pivot]
        return quicksort(less) + [pivot] + quicksort(greater)
print quicksort([10,5,2,3])

5 散列表(hash table)

散列表由键和值组成,散列表将键映射到值
键是唯一的,不重复
缓存/记住数据,以免服务器再通过处理来生成它们

散列函数用于构建键到内存地址的映射,实现O(1)查找
散列函数要将键均匀映射到散列表不同位置
散列函数要尽量减少冲突,就是减少存储的链表长度

6 广度优先搜索(Breadth-first search, BFS)

  • 广度优先搜索思想
    广度优先搜索用于找寻最短距离,适合用于图查找
    广度优先搜索回答两个问题:解的存在性和解的最优性
    对于检查过的人,务必不要再去检查,否则可能导致无限循环
    建立搜索列表依次进行检查
  • 队列
    队列思想是先进先出(First In First Out,FIFO)
    支持两种操作:入队和出队

7 狄克斯特拉算法

  • 加权图和非加权图
    带有权重边的关联图称为加权图
    不带权重边的关联图称为非加权图
  • 有向图和无向图
    边为单一方向,称为有向图
    边为双向,称为无向图
    无向图,每条边都是一个环
  • 狄克斯特拉算法
    狄克斯特拉算法用于求解加权有向无环图最短路径
    且这里的加权图不能是负权,负权需用贝尔曼福德算法(Bellman-Ford algorithm)求解

步骤包括:
(1)找出当前位置(已遍历节点)可到达的代价最小的节点
(2)对于每个节点,检查其邻居,判断是否存在更短路径,如有则更新其开销
(3)重复(1)(2),直至遍历所有节点的可达路径
(4)计算最终路径

8 贪婪算法

  • 贪婪算法思想
    贪婪算法很简单:每步都采取最优的做法
    每步都选择局部最优解,最终得到的不一定是全局最优解
    使用贪婪算法可得到非常接近的解
    贪婪算法的时间复杂度往往较低
    经典问题:任务排序问题、背包问题

  • NP完全问题
    NP完全问题的简单定义是,以难解著称的问题,如旅行商问题和集合覆盖问题
    旅行商问题的解空间是关于城市个数n的阶乘函数,求解的时间复杂度是阶乘时间,远大于多项式时间,很多非常聪明的人都认为,根本不可能编写出可快速解决这些问题的算法
    面临NP完全问题时,最佳的做法是使用近似算法

    NP完全问题难以判断,常具有的特征包括:
    (1)随着元素增加,求解时间迅速增加
    (2)所有涉及组合问题
    (3)不能划分小问题
    (4)涉及序列且难以解决
    (5)涉及集合且难以解决

9 动态规划

  • 动态规划思想
    将问题划分为小问题,并从处理小问题着手
    每种动态规划解决方案都涉及网格
    动态规划可在给定约束条件下找到最优解
    在问题可分解为彼此独立且离散的子问题时,就可使用动态规划来解决
    最优解可能导致背包没装满

  • 经典问题:背包问题
    背包问题的范式是:给定固定的容量约束,选择最大价值的物件组合
    求解思路:双层循环,外层遍历物件,内层遍历容量,判断在该容量下能否装入物件的最大价值
    背包问题与排列顺序无关

  • 绘制网格
    思考下面问题:
    - 单元格中的值是什么?
    - 如何将这个问题划分为子问题?
    - 网格的坐标轴是什么?
    单元格中的值通常就是你要优化的值。
    每个单元格都是一个子问题,因此你需要考虑如何将问题分解为子问题
    没有放之四海皆准的计算动态规划解决方案的公式

  • 应用广泛
    git diff指出两个文件的差异,也是使用动态规划实现的
    编辑距离(levenshtein distance)指出了两个字符串的相似程度,也是使用动态规划计算得到的

10 K最近邻(k-nearest neighbours,KNN)

  • K最近邻的要素
    特征抽取:将物品(如水果或用户)转换为一系列可比较的数字
    衡量相似程度:距离公式、余弦相似度
    实现目的:推荐系统

  • 分类和回归
    分类就是编组
    回归就是预测结果
    KNN用于分类和回归,需要考虑最近的邻居

11 接下来如何做

概述本书未介绍的10种算法以及它们很有用的原因

二叉查找树(binary search tree)的数据结构可以便于查找
二叉树即每个节点最多只有左右两个子节点,左子节点的值都比它小,而右子节点的值都比它大
二叉查找树中查找节点时,平均运行时间为O(log n),但在最糟的情况下所需时间为O(n)
二叉查找树的插入和删除操作的速度很快,但不支持随机访问
平衡二叉树(红黑树、B树)等避免出现性能不佳的糟糕情况

  • 反向索引(inverted index)

反向索引常用于创建搜索引擎

  • 傅里叶变换

傅里叶变换的一个绝佳比喻:给它一杯冰沙,它能告诉你其中包含哪些成分
给定一首歌曲,傅里叶变换能够将其中的各种频率分离出来
傅里叶变换非常适合用于处理信号,可使用它来压缩音乐(过滤低频分量)

  • 并行算法
    并行算法设计起来很难,速度的提升并非线性的

(1)并行性管理开销:分配任务,合并结果
(2)负载均衡:均匀分配任务

  • MapReduce
    MapReduce是一种流行的分布式算法,可通过流行的开源工具Apache Hadoop来使用它
    分布式算法非常适合用于在短时间内完成海量工作,其中的MapReduce基于两个简单的理念:映射(map)函数和归并(reduce)函数

  • 布隆过滤器和HyperLogLog
    布隆过滤器是一种概率型数据结构,它提供的答案有可能不对,但很可能是正确的。为判断网页以前是否已搜集,可不使用散列表,而使用布隆过滤器。使用散列表时,答案绝对可靠,而使用布隆过滤器时,答案却是很可能是正确的
    布隆过滤器的优点在于占用的存储空间很少

  • 安全散列算法(secure hash algorithm,SHA)
    采用一种映射对数据进行变换,可用于加密

  • 局部敏感的散列算法

对字符串做细微的修改,Simhash生成的散列值也只存在细微的差别,用于比对文件

  • Diffie-Hellman 密钥交换
    对消息进行加密
    Diffie-Hellman使用两个密钥:公钥和私钥,使用公钥对其进行加密,加密后的消息只有使用私钥才能解密

(1) 双方无需知道加密算法。他们不必会面协商要使用的加密算法。
(2) 要破解加密的消息比登天还难

  • 线性规划
    线性规划是最简单的最优化算法,用于求解线性约束下的最值问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安、管理、教学、环境等多个方面,构建了一个面的校园应用生态系统。这包括智慧安系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安和智慧管理的重要性。智慧安管理通过分布式录播系统和紧急预案一键启动功能,增强校园安预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值