【算法】学习笔记(0):算法初探(逻辑抽象 + 示例 + 代码实现)

什么是算法?

人生皆算法,算法的本质,是解决问题的方法,遇到问题,寻找答案,解决问题,是作为一个人,一生都在做的事情。

算法是人类思维的产物,是解决问题的方案,并且,它能够映射到计算机世界去实现,完成一些人类不擅长的事情,比如大量重复的计算。

算法很有魅力,它很特别,但是并不神秘,我们时时刻刻都在运用着算法背后的“解决问题”的思想去生活,去过着每一天。

用计算机思维去思考问题

算法是普通的,也是特别的,它是人类使用计算机思维思考的产物,能够让人类更加充分地利用计算机这个人类发明的工具,这也是信息时代特有的产物。

既然是计算机思维,当然有其特点:
在这里插入图片描述概念不重要,理解即可,不必记忆,不必急于掌握,直接看实例体会。

“玩具”问题

计数:判断一个byte(无符号整数)里面有多少个bit的值是1

算法一

很简单的想法,将十进制数转换为一位一位的二进制,然后看看是不是1就好了,就是简单的数数

// method 1
int cal_1(unsigned char number) {unsigned char count = 0;while (number != 0){int div = number % 2;if (div == 1) {count++;}number /= 2;}return count;
}

算法二

上面是我们解决问题的第一种想法。

下面我们加一种假设,假如内存空间足够大,且使用函数次数足够多,我们是不是可以提高算法的效率?

要知道,1字节大小的无符号整数,一共28 = 256种,如果我们连续10000次调用函数,每一次都使用除二取余法(算法1),就大量重复计算了,这个时候不妨提前算好把结果存起来,然后直接访问结果(就像缓存、cache那样的思想)。

也就是所谓的打表查表

// 计数:判断一个byte(无符号整数)里面有多少个bit的值是1
#include <iostream>
using namespace std;int num_table[256] = { 0 };// method 1
int cal_1(unsigned char number) {unsigned char count = 0;while (number != 0){int div = number % 2;if (div == 1) {count++;}number /= 2;}return count;
}// method 2
int cal_2(unsigned char number) {return num_table[number];
}int main(){// 存储答案for (unsigned char i = 0; i < 255; i++) {num_table[(int)i] = cal_1(i);}// 直接访问cout << cal_2(15);return 0;
}

我们开始使用算法1,存储了一张,之后再需要使用的时候,就能够直接查表得结果,而不需要再重复计算了,如果调用100000万次,效率将会比算法1显著提高。

当然……由于数据量对计算机来说太小了还是,测试不出很大的差异其实。

如果规模更大,会有显著效果。

算法三

对于算法一

  • 省空间,因为没占用多少数据段
    对于算法二
  • 省时间,因为提前储存好了答案,只需要访问数组就可以

对于前面两种算法,是根据不同需求不同情况取使用的,但是涉及到了算法设计考虑的两个维度:时间和空间

算法一省空间,费时间,算法二省时间废空间,那么能不能兼得?

其实这种

不走极端取中间的兼得思想

在计算机中经常需要用到。

我们需要既省时间又省空间的算法。

与cache类似的设计思想

我们可以使用哈希表,采取如下策略

  • 如果表中有值,那就直接取
  • 如果没有,就去计算,并且存表中

这样一来,做到了拿走需要的,保存需要的,同时考虑了时间和空间两方面的因素。

我们使用unordered_map完成这件事:

// 计数:判断一个byte(无符号整数)里面有多少个bit的值是1
#include <iostream>
#include <unordered_map>
using namespace std;typedef std::unordered_map<unsigned char, int> result_map;// method three
int cal_3(unsigned char number, result_map &map) {result_map::iterator count = map.find(number);if (count != map.end()) // 在无序映射表中{cout << "在表中  ";return	count->second;}else  // 不在表中{cout << "不在表中  ";int result = cal_1(number);map.insert(result_map::value_type(number,result));	// 插入键值对return result;}}int main(){result_map map;cout << cal_3(15, map) << endl;	// 不在表中  4cout << cal_3(15, map) << endl; // 在表中    4cout << cal_3(10, map) << endl; // 不在表中  2cout << cal_3(10, map) << endl; // 在表中    2return 0;
}

这样,通过无序映射表,我们就完成了既节省时间,又节省空间的目的。

小结

我们来回顾一下。

对于这个问题

  1. 我们看到了问题,理解了问题
  2. 拆解问题,变成自己熟悉的
  3. 解决问题,创建解决问题的过程方案
  4. 设计解决流程,将其代码实现
  5. 根据实际情况,优化解决方案
  6. 综合考虑算法的时间空间两个维度的指标

我们通过这个超级简单的例子,初步了解了算法的基本情况,我们继续往下进行。

连续子序列和

在这里插入图片描述
让我们体会一下不同的算法,不同的解决方案,感受一下它们之间的时间和空间上的性能差异。

一件事情,往往都是很多种解决方案,并且都能到达彼岸,但是过程不一样,走过的路不同,花的时间也不同,算法的时空性能也是一样的。

充分体会: 计算机世界是人类世界的二进制映射,与人类生活息息相关。

算法1:三层循环

  1. 取某个首位置i
  2. i后的某个位置j
  3. 计算[i,j]数值的和,与最大值比较,更新最大值

这是一种最朴素的思想了,我们看图。
在这里插入图片描述因此,我们需要

for(int i = 0; i < char_size; i++){for(int j = i; j < char_size; j++){1. 求和2. 更新maxValue}
}

代码如下:

#include <iostream>
#include <vector>
using namespace std;int max_subsequence_sum(const vector<int> &a) {int max_sum = 0;for (int i = 0; i < a.size(); i++) {for (int j = i; j < a.size(); j++) {int current_sum = 0;for (int k = i; k <= j; k++)current_sum += a[k];if (current_sum > max_sum)max_sum = current_sum;}}return max_sum;
}int main()
{vector<int> a = { 1,3,-1,2 };cout << max_subsequence_sum(a);return 0;
}

但是,毫无疑问,三重循环,时间消耗过多了,我们得看看能不能优化。
在这里插入图片描述将三重循环转换为递归。

代码暂不写

算法2:两层循环

在这里插入图片描述

算法3:一层循环

在这里插入图片描述

算法4:递归

在这里插入图片描述

算法比较

在这里插入图片描述

小结

之所以没有谈及后面的代码,因为对于初学者来说比较复杂,看看就行了,充分体会的是同一个问题,达成同一个目的的情况下,不同算法的差异巨大,这也是算法魅力所在。

致谢

感谢北交大算法MOOC!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Verilog】数据流建模传输问题:赋值传输有方向

这次&#xff0c;我们说明的是&#xff0c;assign语句实现的数据流建模&#xff0c;包含的是两个层面 建立联系传输方向 assign A B的本质含义是 A与B建立关联B的值传给A 这个传输方向至关重要&#xff0c;实际情况是什么&#xff0c;就必须按照顺序进行&#xff0c;不是单…

【计算机系统设计】实践笔记(2)数据通路构建:第一类R型指令分析(2)

待办事项 时钟频率高&#xff0c;取指周期长&#xff0c;远大于执行周期&#xff0c;如何处理&#xff1f; 不可综合逻辑的处理 接上一篇 【计算机系统设计】实践笔记&#xff08;2&#xff09;数据通路构建&#xff1a;第一类R型指令分析&#xff08;1&#xff09; 8.2 ALU运…

【计算机系统设计】实践笔记(2)插叙:综合与实现

接上一篇文章的第10节 之前完成了功能仿真&#xff0c;下面我们进行综合实现。 10.1.1 综合 综合成功。 实现试试 这真是令人悲伤……找Bug吧。 我们看看综合后的门级网表。 发现综合后的并不是我们想要的……看了看可能是综合的目录错误&#xff0c;我们再试试。 不是这…

【电路原理】学习笔记(1):电路模型的基本变量

上一讲说到了电路模型&#xff0c;这一电路的抽象&#xff0c;现在我们看看它的基本组成。 1 电流 1.1 概念 对于一根管道&#xff0c;它能够流通电荷&#xff0c;定向移动就形成了电流。 单位时间t内&#xff0c;&#xff0c;某一横截面&#xff0c;穿过电荷量是q&#xf…

【电路原理】学习笔记(0):电路与电路模型

东北大学电路原理MOOC 电路原理的核心点&#xff1a;研究电路模型 我们实际看见的&#xff0c;是真实电路 我们高中学的&#xff0c;是电原理图 现在&#xff0c;我们要研究的是电路模型&#xff0c;它是实际电路的抽象模型&#xff0c;并且是理想化的。 对于电路模型&#…

【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析

0 回顾 前面的内容中&#xff0c;第一类R型指令分析&#xff0c;我们完成了一类R型指令的设计&#xff0c;完成了其数据通路&#xff0c;构建了相应的部件&#xff0c;并且完成了从ROM中取指&#xff0c;成功进行了基本的功能仿真&#xff0c;进行了综合和实现&#xff0c;但是…

【计算机系统设计】实践笔记(3)改进数据通路:jr指令分析与实现

1 jr指令分析 instructionoprsrtrdshamtfuncjr000000rs000000000000000001000 举例&#xff1a;jr $31 功能&#xff1a;PC <- &#xff08;$31&#xff09; 这是个跳转指令&#xff0c;将指定寄存器的值&#xff0c;放入PC中&#xff0c;是无条件跳转。 我们需要 更新P…

【计算机系统设计】实践笔记(4)改进数据通路:第一类I型指令分析与实现

0 回顾 之前&#xff0c;我们完成了17条R型指令的设计&#xff0c;接下来&#xff0c;我们逐步完成I型指令的设计。 1 核心思想&#xff1a;增量思维 & 复用思维 & 学会选择 & 分治思想 增量思维 我们从无到有&#xff0c;构建了支持R型指令的CPU&#xff0c;接…

【算法】学习笔记(2):递归思想

0 回顾 之前的笔记&#xff08;0&#xff09;和笔记&#xff08;1&#xff09;&#xff0c;我们介绍了算法的基本含义&#xff0c;并且举了一些实例&#xff0c;同时理解了&#xff0c;算法就是人类在教计算机做事情&#xff01; 我们知道&#xff0c;算法就是解决问题的方案…

【计算机系统设计】实践笔记(5)改进数据通路:beq和bne指令分析与实现

接下来的分析和实践非常粗糙&#xff0c;因为跟之前一样的分析流程&#xff0c;不再多说了&#xff0c;如果前面真的掌握&#xff0c;这里不看也罢。 分析 先看beq指令。 ALU输入的是rs和rt&#xff0c;不输入imm&#xff0c;进行subu操作&#xff0c;判断是否为zero&#x…

【算法】学习笔记(4):分治思想 归并排序

分治思想&#xff0c;分治策略&#xff0c;自古有之&#xff0c;与人类生活息息相关&#xff0c;其本质是将大问题拆解为小问题&#xff0c;小问题转换为已知解的问题&#xff0c;进而求解。 军队管理&#xff0c;国家分级治理…… 大规模数据排序&#xff0c;例如10000000000…

html css 学习笔记(1)背景相关

背景颜色 图片 插入图片img背景图片 背景图片 3. logo 4. 大图 5. 装饰性小图 便于控制位置&#xff01; 插入后会执行自动平铺&#xff0c;这与插入图片是不同的&#xff01; div{width: 600px;height: 300px;background-image: url(img/登录用户头像.png); }小结 盒子的第…

2020-12-15 CPU设计复盘

SOC修改 将之前完成的31条指令单周期CPU进行了重构&#xff0c;将其分开&#xff0c;实现了内外有别&#xff0c;将CPU、指令ROM和数据RAM。 这样&#xff0c;以后为其增加接口外设&#xff0c;总线控制&#xff0c;才更加清晰&#xff0c;这是进一步封装和抽象。 MARS大坑 …

Tomcat 学习笔记(0)

JavaWeb 用Java写的程序&#xff0c;可以在浏览器运行。 Request & Responce Web资源 Web服务器 我们在自己的主机启动Tomcat服务器&#xff0c;然后运行它&#xff0c;就能够通过主机访问这个服务器&#xff0c;这个服务器能够运行我们的程序。 部署Web工程 法1 将web…

计算机系统 学习笔记(0)南京大学(一)第一周

课程&#xff1a;计算机系统基础 核心理念&#xff1a;人类世界与计算机世界的异同 人类世界 直观感受数学 计算机世界 与数学不同&#xff0c;存储首先&#xff0c;各层次与现实世界不同 我们关注点是差异点&#xff01; 一样的你就不用关心了&#xff0c;关心差异&#…

x86架构下 CF与OF标志位 带符号和无符号运算 详解

针对能够影响OF和CF标志位的指令&#xff0c;一般来说是涉及到数据运算的指令&#xff0c;这里使用add举例&#xff0c;即不区分有无符号的加法指令&#xff0c;参与运算的数据&#xff0c;从二进制层级去考虑。 CF标志位 对于CF&#xff0c;它是carry flag&#xff0c;进位标…

tmux学习笔记

参考学习链接 我们需要理解几个重要的概念 session 回话window 窗口pane 窗格 window 我们打开的一个terminal就是一个window. 而打开的这个window&#xff0c;也就是打开了一个session&#xff0c;打开window&#xff0c;session开始&#xff1b;关闭window&#xff0c;se…

Linux的ext4文件系统学习笔记

补充&#xff1a;设备独立性 Linux中&#xff0c;设备驱动以文件形式表示&#xff0c;用户操作逻辑设备就是操作文件&#xff0c;而不是具体的物理设备&#xff0c;也就是说&#xff0c;用户操作的是功能&#xff0c;是黑箱&#xff0c;而不是真正的实体。 APP操作的都是逻辑…

html基础元素案例笔记(1)

这是代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>CSS FlexBox test</title><link rel"stylesheet" type"text/css" href"./css/index.css"></head><body>…

C语言中的struct和union区别

参考&#xff1a;Difference between Structure and Union in C 二者区别 struct 这里不做详细说明&#xff0c;因为参考链接中都写明了。只做一些重点强调。 struct中声明的变量&#xff0c;在分配空间的时候&#xff0c;struct结构空间大小&#xff0c;大于等于其内部所有…