数据结构与算法之美,算法面试通关40讲 覃超 Leetcode 题目总结(未完待续)
数据结构与算法之美,算法面试通关40讲 覃超 Leetcode 题目总结(未完待续)详细介绍
本文目录一览: 数据结构与算法之美笔记——散列表(上)
摘要:
我们已经知道随机访问数组元素时间复杂度只有 ,效率极高,当我们想利用数组的这个特性时就需要将元素下标与存储信息对应。例如,一个商店只有四件商品,依次编号 0 至 3,这样就可以将四件商品信息按照编号对应下标的方式存储到数组中,依据编号就可以快速从数组中找到相应商品信息。
如果一段时间之后,商店盈利并且重新进货 100 件商品,商家想对大量商品在编号上区分类别,这时候需要使用类别编号加顺序编号的方式标识每件商品,这种编号变得复杂,并不能直接对应数组下标,此时的商品编号又该如何对应数组下标以实现快速查找商品的功能?这时候我们可以将类别编号去除之后按照顺序编号对应数组下标,同样也能享受数组高效率随机访问的福利。这个例子中,商品编号称为「 键 」或「 关键字 」,将键转化为数组对应下标的方法就是「 散列函数 」或「 Hash 函数 」,由散列函数生成的值叫做「 散列值 」或「 Hash 值 」,而这样的数组就是散列表。
从散列表的原理来看,数据通过散列函数计算得到散列值是关键,这个步骤中散列函数又是其中的核心,一个散列函数需要遵守以下三个原则。
因为散列函数生成的散列值对应数组下标,而数组下标就是非负整数,所以需要满足第一个原则;两个相等的数据经过散列算法得到的散列值肯定相等,否则利用散列值在散列表中查找数据就无从谈起;至于第三个原则虽然在情理之中,却不那么容易做到,即使是被广泛运用的散列算法也会出现散列值冲突的情况,导致无法满足第三个原则。
散列函数作为散列表的核心部分,必然不能拖散列表的执行效率后腿,毕竟散列表的查询、插入和删除操作都需要经过散列函数,所以散列函数不能太复杂,执行效率不能太低。由于散列函数不可避免地都会出现散列冲突情况,散列函数要尽量降低散列冲突,使散列值能够均匀地分布在散列表中。
解决散列冲突主要有「 开放寻址 」(open addressing)和「 链表法 」(chaining)两类方法。
开放寻址法是指插入操作时,当生成的散列值对应槽位已经被其他数据占用,就探测空闲位置供插入使用,其中探测方法又分为「 线性探测 」(Linear Probing)、「 二次探测 」(Quadratic Probing)和「 双重散列 」(Double hashing)三种。
线性探测是其中较为简单的一种,这种探测方式是当遇到散列冲突的情况就顺序查找(查找到数组尾部时转向数组头部继续查找),直到查找到空槽将数据插入。当进行查找操作时,也是同样的操作,利用散列值从散列表中取出对应元素,与目标数据比对,如果不相等就继续顺序查找,直到查找到对应元素或遇到空槽为止,最坏情况下查找操作的时间复杂度可能会下降为 。
散列表除了支持插入和查找操作外,当然也支持删除操作,不过并不能将需删除的元素置为空。如果删除操作是将元素置为空的话,查找操作遇到空槽就会结束,存储在被删除元素之后的数据就可能无法正确查找到,这时的删除操作应该使用标记的方式,而不是使用将元素置空,当查找到被标识已删除的元素将继续查找,而不是就此停止。
线性探测是一次一个元素的探测,二次探测就是使用都是线性探测的二次方步长探测。例如线性探测是 ,那二次探测对应的就是 。
双重探测是当第一个散列函数冲突时使用第二个散列函数运算散列值,利用这种方式探测。例如,当 冲突时,就使用 计算散列值,如果再冲突就使用 计算散列值,依此类推。
关于散列表的空位多少使用「 装载因子 」(load factor)表示,装载因子满足数学关系 ,也就是说装载因子越大,散列表的空闲空间越小,散列冲突的可能性也就越大,一般我们会保持散列表有一定比例的空闲空间。
为了保持散列表一定比例的空闲空间,在装载因子到达一定阈值时需要对散列表数据进行搬移,但散列表搬移比较耗时。你可以试想下这样的步骤,在申请一个新的更大的散列表空间后,需要将旧散列表的数据重新通过散列函数生成散列值,再存储到新散列表中,想想都觉得麻烦。
散列表搬移的操作肯定会降低散列表的操作效率,那能不能对这一过程进行改进?其实可以将低效的扩容操作分摊至插入操作,当装载因子达到阈值时不一次性进行散列表搬移,而是在每次插入操作时将一个旧散列表数据搬移至新散列表,这样搬移操作的执行效率得到了提高,插入操作的时间复杂度也依然能保持 的高效。当新旧两个散列表同时存在时查询操作就要略作修改,需先在新散列表中查询,如果没有查找到目标数据再到旧散列表中查找。
当然,如果你对内存有更高效的利用要求,可以在装载因子降低至某一阈值时对散列表进行缩容处理。
除了开放寻址之外,还可以使用链表法解决散列冲突的问题。散列值对应的槽位并不直接存储数据,而是将数据存储在槽位对应的链表上,当进行查找操作时,根据散列函数计算的散列值找到对应槽位,再在槽位对应的链表上查找对应数据。
链表法操作的时间复杂度与散列表槽位和数据在槽位上的分布情况有关,假设有 n 个数据均匀分布在 m 个槽位的散列表上,那链表法的时间复杂度为 。链表法可以不用像开放寻址一样关心装载因子,但需要注意散列函数对散列值的计算,使链表结点能够尽可能均匀地分布在散列表槽位上,避免散列表退化为链表。有时黑客甚至会精心制造数据,利用散列函数制造散列冲突,使数据集中某些槽位上,造成散列表性能的极度退化。
面对这样的恶意行为散列表只能坐以待毙吗?其实不然,当槽位上的链表过长时,可以将其改造成之前学习过的跳表等,链表改造为跳表后查询的时间复杂度也只是退化为 ,依然是可以接受的范围。
链表法在存储利用上比开放寻址更加高效,不用提前申请存储空间,当有新数据时申请一个新的结点就行。而且链表法对装载因子也不那么敏感,装载因子的增高也只是意味着槽位对应的链表更长而已,链表增长也有将链表改造为跳表等结构的应对策略,所以链表法在装载因子超过 1 的情况下都可保持高效。
开放寻址不存在像链表法一样有链表过长而导致效率降低的烦恼,不过装载因子是开放寻址的晴雨表,装载因子过高会造成散列冲突机率的上升,开放寻址就需要不断探测空闲位置,算法的执行成本会不断被提高。而且在删除操作时只能将数据先标记为删除,对于频繁增删的数据效率会受到影响。
当然也可以在这种风险出现前进行散列表的动态扩容,不过这样就会出现大量空闲的存储空间,导致存储的利用效率过低,这种现象在数据量越大的情况下越明显。所以开放寻址比较适用于数据量较小的情况。
链表法对于散列冲突的处理更加灵活,同时对存储空间的利用效率也更高,但链表结点除了存储数据外还需要存储指针,如果存储数据较小指针占用的存储甚至会导致整体存储翻倍的情况,但存储数据较大时指针占用的存储也就可以忽略不计,所以链表法较适合存储数据对象较大,但频繁的增删操作不会对链表法造成明显的影响。因为这样的特点,链表法更加适合大数据量,或者数据对象较大的时候,如果数据操作频繁,那链表法更是不二之选。
散列表由数组扩展而来,使用散列函数将键计算为散列值,散列值对应数据存储的数组下标。虽然散列表的执行效率较高,但会有散列冲突的问题,可以通过开放寻址法和链表法解决此问题。
开放寻址存储利用效率较低,适用数据量较小并且增删不频繁的情况,如果数据量较大,增删频繁的情况更加适用链表法,相对之下链表法更加普适。
如何靠自学提升自己的编程能力?
1、注重基础知识
编程基础知识是提高编程能力的重要基石,如掌握常用编程语言、数据结构和算法等。因此,在开始编程之前,我们需要花费时间深入了解这些基础知识,以便更好地理解程序逻辑并提高编写代码的效率。
2、阅读高质量的代码
阅读高质量的代码可以帮助我们了解其他程序员的编码方式和思维模式,并从中获取灵感和启示。通过观察他人的代码,我们可以从中学习到新的编程技巧和解决问题的方法。
3、刻意练习
刻意练习是提高编程能力的重要方法之一,它包括专注于练习特定的编程技能和应用这些技能来解决实际问题。通过不断地练习,我们可以锻炼自己的编程能力,并在不断的实践中逐渐提高自己的技能水平。
4、参加编程社群或交流会
参加编程社群或交流会是提高编程能力的好方法,可以通过与其他程序员分享经验和思路来提升自己的技能水平。此外,还可以通过这些社群或交流会了解到最新的编程技术和趋势,从而更好地掌握相关技能。
5、坚持学习和实践
学习和实践是提高编程能力的关键所在,我们需要不断地更新自己的知识和技能,并将其应用于实际项目中。只有通过坚持学习和实践,我们才能不断地提高自己的编程能力。
总之,提高编程能力需要付出大量的时间和努力,但只要掌握了正确的方法和技巧,就能够快速有效地提升自己的编程技能。通过注重基础知识、阅读高质量的代码、刻意练习、参加编程社群或交流会以及坚持学习和实践,相信每个人都可以成为一名优秀的程序员。
在当今信息技术高速发展的时代,编程成为了许多人所追求的技能之一。然而,成为一名出色的程序员并不是易事,需要不断学习、实践和探索。那么如何靠自学提升自己的编程能力?接下来我们就来具体了解一下吧。
1、多读好书书籍会系统介绍常见的知识点,读一本书比读100篇博客有用的多。博客的作者技能良莠不齐,所以可能陷入误区。对于基础知识点,阅读好书,学习在线课程,阅读官方文档(React的官网文档,最好是英文文档,中文很多翻译不准确)。这样逐步搭建自己的知识框架。在学习一门新的编程语言时,应该关注这门语言的基本表达形式(Primitive Elements)、组合的方法(Means of Combination)及抽象的方法(Means of Abstraction)这三个特性。
基础知识:基本语法、关键字、变量与常量、数据类型、运算符、流程控制、异常处理、文件处理、编程思想(面向对象、面向过程、函数式编程)、多线程支持等;
应用知识:网络请求、数据处理、内置函数、对日志和调试的支持、对单元测试的支持、序列化与反序列化等;
高级知识:开源类库、开源框架、底层原理等;
我觉得优先读基础知识(Javascript 基础语法,数据结构与算法,ES6语法等),这部分基础知识成熟,是其他所有知识的基础。之后根据工作需求,阅读相关的第三方库文档。
好书推荐
编程语言(c/c++):《c语言程序设计》->《c++ primer》-> C++ efftive 系列 -> 《C++ STL 源码剖析》->《深入理解C++对象模型》
数据结构与算法:《大话数据结构》->《算法图解》->《数据结构与算法之美》 -> 《剑指offer》 -> LeetCode刷题(至少刷到200多道)操作系统:《操作系统导论》->《现代操作系统》
计算机网络:《图解HTTP》->《图解TCP/IP》->《网络是怎么连接的》 ->《计算机网络自顶向下》->《TCP/IP协议详解卷1》
计算机组成:《程序是怎么跑来的》->《计算机组成原理:软件/接口与设计》->《深入理解计算机系统》数据库:《SQL必知必会》->《从根儿上理解mysql》->《mysql技术内幕》->《高性能mysql》
编译原理:《程序员的自我修养》
2、多参与项目参与项目就会写很多的代码。这样可以让你明白学过的知识具体怎么使用,哪些知识比较常用,自己哪些知识学得不牢固。实践是检验真理的唯一标准,项目是检验知识的唯一标准。可以有针对性的参与项目(不同项目主要练习不同的知识点),自己需要做到把经常使用的项目,具体的配置和注意点熟记,不常使用的项目,可以短时间内阅读项目并进行开发。项目推荐:
基千百度AI的语音识别
代码量:400行
实现功能:语音录入、语音转文字
适合人群:有C++、QT、网络基础。
涉及技术:QT、信号与槽、HTTP、百度AI开放平台。
通讯管理系统
代码量:400行
实现功能:通讯录信息的增删改查操作。
适合人群:C语言的初学者,难度较小,不合适写在简历上。综合应用数组、指针,可以锻炼编程逻辑思维,积累代码量。
涉及技术:数组、指针、结构体、函数。
停车管理系统
代码量:800行
实现功能:停车、找车、缴费、离开、路线规划。
适合人群:有C语言和链表、栈、队列基础。
涉及技术:指针、数组、链表、队列、广度优先搜索。
智能WiFi摄像头
代码量:1500行
语言:C语言
实现功能:图像数据采集、APP显示、远程控制
适合人群:有C语言、Linux、网络基础,属干综合性项目,适合有意从事嵌入式开发的同学。
硬件平台: NanoPi Duo2
涉及技术: mjpg-stremer、json、TCP、UDP、QT、epoll
智能音箱
代码量:3000行
实现功能:由嵌入式端、后台云服务器和APP组成,实现了切歌、暂停、继续、音量调节、APP远程控制、语音控制。
适合人群:有C/C++/Linux基础,综合性比较强,可以作为项目提升、毕设、就业等。
硬件平台:mini2440
涉及技术:C/C++、libevnet、json、进程、TCP、QT
3、多阅读源码阅读源代码是学习编程的重要方式之一。通过阅读其他人编写的代码,你可以学习到其他人的编程思路和技巧。同时,阅读源代码还可以帮助你更好地理解编程语言和框架的工作原理。如果你想要学习一个新的编程语言或框架,阅读其源代码是非常有帮助的。
关于源码阅读的三层境界:
初级:记流水账——初期的源码阅读文章基本上是记流水账,例如对源码一行行加注释,只关注底层实现细节,但并未形成更高层次认知,对其设计理念没有提炼与深度领悟。中级:能提问、思考、提炼——要求我们在阅读源码的时候多思考,并反问自己如果自己实现的话该如何着手,如何设计,带着疑问去研究源码。通过对比,思考,会对其背后的理念有了更深刻的理解。高级:思考、质疑、验证——不管是什么代码,都会存在BUG或者实现并不合理的地方,如果大家在阅读源码的时候能够深入思考, 合理质疑,并能通过验证证明自己的观点,说明我们的能力、思考得到了极大的提升。
4、用好搜索引擎
多使用非百度的搜索引擎,可以获取很多英文的参考资料,百度会减弱自己的英文能力。想要快速解决这些问题可以学会使用搜索引擎。编程界有个说法:超级程序员=普通程序员+Google。用好搜索引擎,Google+GitHub也许可以解决你大部分的问题。
Newest ‘python’ Questions—一个与程序相关的IT技术问答网站
3.10.4 Documentation—Python各个版本的官方文档
5、自己做一个开源的项目参与开源项目是提高编程能力的另一种方式。通过参与开源项目,你可以与其他程序员合作,学习到其他人的编程经验和技巧。同时,开源项目还可以帮助你锻炼自己的编程能力,提高自己的编码水平。参与开源项目还可以扩展你的社交圈,结识更多的编程爱好者。
6、学习算法和数据结构
算法和数据结构是编程的基础,它们可以帮助你更好地理解编程语言和框架的工作原理。学习算法和数据结构可以帮助你更好地解决编程问题,同时也可以提高你的编程能力。如果你想要成为一名优秀的程序员,学习算法和数据结构是非常重要的。
个人经验:通过自学提升自己的编程能力需要付出大量的时间和精力,还需要具备自律和耐心。但是,成为一名出色的程序员可以为自己创造更多的机会和发展空间,也可以为社会创造更多的价值和贡献。因此,我们需要不断学习和实践,追求卓越,成为一名优秀的编程高手。
大学数据结构与算法这10本书收好
书籍推荐靠着这10本经典书籍数据结构与算法
《大话数据结构》
《大话数据结构》 这本书最大的特点是,它把理论讲得很有趣,不枯燥。读技术书最大的烦恼不是这本书经典不经典,而是能不能看的进去,能看的进去学到了,这本书就是好书。如果看不进去,哪怕是再经典的书,对学习的能都没有一丁点的帮助,对吧?
《算法图解》
就像这本书副标题写的那样“像小说一样有趣的算法入门书”,主打“图解通俗易懂,学习起来就轻松多了,对吧?
通过《大话数据结构》和《算法图解》两本书的学习,我相信读者朋友们一定能够入门数据结构和算法了。如果还想更系统、更深入地学习,请继续往下看。
《数据结构和算法分析》
黑皮书,一眼看上去,就知道是一本经典书,对吧?《数据结构和算法分析》这本书的作者也非常用例子不仅有 Java 版的,还有 C 版和 C++ 版的
《剑指 offer》
这本书剖析了 80 个典型的编程面试题,如果能搞懂这本书里的内容,应付一般公司的面试应该不成问题。
直白点说,学习算法和数据结构会非常辛苦,那既然付出了这么多心血,我们的目的就很明确,获得一份更好的工作岗位,这本书一定能够帮助到我们
《趣学数据结构》
讲解比较生动,用 C++ 描述的,适合基础一般的初学者。作者陈小玉是河南的,还写过另外一本算法方面的书,同样很适合初学者
《啊哈算法》
一本有趣的算法入门书,C 语言实现的,没有枯燥的描述,没有难懂的公式,一切以实际应用为出发点。
《漫画算法 : 小灰的算法之旅》
用漫画的形式讲述了算法和数据结构的基础知识复杂多变的算法面试题目及算法的实际应用场景。出了两版,一版 Python,一版 Java
《程序员代码面试指南》
这是一本程序员代码面试”神书”!书中对 IT 名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现,选取将近 300 道真实出现过的经典代码面试题,”刷”完这书,就是”题王”!
《算法》
这是一本非常适合于自学以及作为教材的算法书特点有: 基础非常全面、图示清晰易懂、数学要求低代码是通过 Java 实现的,虽然是一本大部头书,但难懂的话不过。
《数据结构与算法之美》
会介绍最常见、最重要的数据结构与算法。每种都从“来历”“特点”“适合解决的问题”“实际的应用场景出发,进行详细介绍:并配有清晰易懂的手绘图解,由浅入深进行讲述:还适时总结一些实用“宝典”教你解决真实开发问题的思路和方法
算法面试通关40讲 覃超 Leetcode 题目总结(未完待续)
主要是自己收集的题目,正在学习王争老师的数据与算法结构之美和覃超老师的算法面试通关四十讲,两位老师推荐很经典的面试题。所以为了方便自己,在这里做一个汇总。如果对你有帮助那当然好,或者也可以看参考资料,里面有很多优秀的Github的资源。
参考资料 算法复杂度查看: https://www.bigocheatsheet.com/ C语言解法推荐: https://github.com/begeekmyfriend/leetcode Java解法推荐: https://github.com/azl397985856/leetcode 数据结构与算法之美(王争)(有各种语言的版本): https://github.com/wangzheng0822/algo Github 40K star leetcode: https://github.com/azl397985856/leetcode Github 13K star Leetcode: https://github.com/haoel/leetcode Github 63K star 用动画的形式呈现解LeetCode题目的思路: https://github.com/MisterBooo/LeetCodeAnimation python 解法: https://github.com/qiyuangong/leetcode 其他解法: https://github.com/qiyuangong/leetcode
06|面试题:反转一个单链表&判断链表是否有环
数据与算法结构之美: 21 Merge Two Sorted Lists 【 C 】【 python 】 删除链表倒数第 n 个结点 【 Leetcode 的解题 】 求链表的中间结点 Middle of the Linked List
20 Valid Parentheses 232 Implement Queue using Stacks 【 C 】【 My C solution 】 225 Implement Stack using Queues 【 C 】
703 Kth Largest Element in a Stream 239 Sliding Window Maximum
242 Valid Anagram 1 Two Sum 【 C 】 15 3Sum 18 4Sum
98 Validate Binary Search Tree 235 Lowest Common Ancestor of a Binary Search Tree 236 Lowest Common Ancestor of a Binary Tree
50 Pow(x, n) 169 Majority Element
122 Best Time to Buy and Sell Stock II
冒泡排序,选择排序,插入排序,供参考:【 C 】
(未完待续,大概等我做完上面这些就可以继续补充剩下的了吧)
数据结构学的到底是什么,和算法的关系
所有的算法,乃至数学在实际运用中都是要根据不同的数据来选择不同的方法,所以一般学习过算法和数据结构的人都会越发的认识到,数据才是程序的中心,只有找到了一个组织数据的最佳方式,算法的运用才会事半功倍。
一般来说我觉得先学算法比较好,但算法和数据结构都是相辅相成的,要学好算法要有一定数据结构的基础,要学数据结构亦要有算法基础。但算法比数据结构更重要一些,因为没有算法只有数据结构是没用的。
数据结构是在整个计算机科学与技术领域上广泛被使用的术语。它用来反映一个数据的内部构成,即一个数据由那些成分数据构成,以什么方式构成,呈什么结构。
从计算机的角度讲,程序是用一种计算机能理解并执行的计算机语言描述解决问题的方法步骤。程序设计:是分析解决问题的方法步骤,并将其记录下来的过程。算法:解决问题的方法步骤。
1.数据结构或者算法之类不是直接运行的东西。 数据结构,大约就是关于怎样使用变量能更有效率的理论。 算法么,比较象数学公式,不过代进去的不是数据或变量,而是C的语句。是关于怎样安排程序才能事半功倍的理论。
本人乃一个数据痴迷者,在计算机的道路上,也是一个数据结构的痴迷者,现在大学里面和同学搞开发也痴迷于数据库,我就我个人的理解给你谈一谈:
首先,数据结构是一门计算机语言学的基础学科,它不属于任何一门语言,其体现的是几乎所有标准语言的算法的思想。
上面的概念有一些模糊,我们现在来具体说一说,相信你门的数据结构使用的是一门具体的语言比如C/C++语言来说明,那是为了辅助的学习数据结构,而数据结构本身不属于任何语言(相信你把书上的程序敲到电脑里面是不能通过的吧,其只是描述了过程,要调试程序,还需要修改和增加一些东西)。你们的书上开始应该在讲究数据的物理存储结构/逻辑存储结构等概念,说明数据结构首先就是“数据的结构”,在内存上的存储方式,就是物理的存储结构,在程序使用人员的思想上它是逻辑的,比如:
你们在C/C++中学习到链表,那么链表是什么一个概念,你们使用指针制向下一个结点的首地址,让他们串联起来,形成一个接一个的结点,就像显示生活中的火车一样。而这只是对于程序员的概念,但是在内存中存储的方式是怎样的那?对于你程序员来说这是“透明”的,其内部分配空间在那里,都是随机的,而内存中也没有一个又一根的线将他们串联起来,所以,这是一个物理与逻辑的概念,对于我们程序员只需要知道这些就可以了,而我们主要要研究的是“逻辑结构”。
我可以给你一个我自己总结的一个概念:所有的算法必须基于数据结构生存。也就是说,我们对于任何算法的编写,必须依赖一个已经存在的数据结构来对它进行操作,数据结构成为算法的操作对象,这也是为什么算法和数据结构两门分类不分家的概念,算法在没有数据结构的情况下,没有任何存在的意义;而数据结构没有算法就等于是一个尸体而没有灵魂。估计这个对于算法的初学者可能有点晕,我们在具体的说一些东西吧:
我们在数据结构中最简单的是什么:我个人把书籍中线性表更加细化一层(这里是为了便于理解在这样说的):单个元素,比如:int i;这个i就是一个数据结构,它是一个什么样的数据结构,就是一个类型为int的变量,我们可以对它进行加法/减法/乘法/除法/自加等等一系列操作,当然对于单个元素我们对它的数据结构和算法的研究没有什么意义,因为它本来就是原子的,某些具体运算上可能算法存在比较小的差异;而提升一个层次:就是我们的线性表(一般包含有:顺序表/链表)那么我们研究这样两种数据结构主要就是要研究它的什么东西那?一般我们主要研究他们以结构为单位(就是结点)的增加/删除/修改/检索(查询)四个操作(为什么有这样的操作,我在下面说到),我们一般把“增加/删除/修改”都把它称为更新,对于一个结点,若要进行更新一类的操作比如:删除,对于顺序表来说是使用下标访问方式,那么我们在删除了一个元素后需要将这个元素后的所有元素后的所有元素全部向前移动,这个时间是对于越长的顺序表,时间越长的,而对于链表,没有顺序的概念,其删除元素只需要将前一个结点的指针指向被删除点的下一个结点,将空间使用free()函数进行释放,还原给操作系统。当执行检索操作的时候,由于顺序表直接使用下标进行随机访问,而链表需要从头开始访问一一匹配才可以得到使用的元素,这个时间也是和链表的结点个数成正比的。所以我们每一种数据结构对于不同的算法会产生不同的效果,各自没有绝对的好,也没有绝对的不好,他们都有自己的应用价值和方式;这样我们就可以在实际的项目开发中,对于内部的算法时间和空间以及项目所能提供的硬件能力进行综合评估,以让自己的算法能够更加好。
(在这里只提到了基于数据结构的一个方面就是:速度,其实算法的要素还应该包括:稳定性、健壮性、正确性、有穷性、可理解性、有输入和输出等等)
为什么要以结点方式进行这些乱七八糟的操作那?首先明确一个概念就是:对于过程化程序设计语言所提供的都是一些基础第一信息,比如一些关键字/保留字/运算符/分界符。而我们需要用程序解决现实生活中的问题,比如我们要程序记录某公司人员的情况变化,那么人员这个数据类型,在程序设计语言中是没有的,那么我们需要对人员的内部信息定义(不可能完全,只是我们需要那些就定义那些),比如:年龄/性别/姓名/出生日期/民族/工作单位/职称/职务/工资状态等,那么就可以用一些C/C++语言描述了,如年龄我们就可以进行如下定义:
int age;/*age变量,表示人员公司人员的年龄*/
同理进行其他的定义,我们用结构体或类把他们封装成自定义数据类型或类的形式,这样用他们定义的就是一个人的对象的了,它内部包含了很多的模板数据了。
我就我个人的经历估计的代码量应该10000以内的(我个人的经理:只是建议,从你的第一行代码开始算,不论程序正确与否,不论那一门语言,作为一个标准程序员需要十万行的代码的功底(这个是我在大学二年级感觉有一定时候的大致数据,不一定适合其他人),而十万行代码功底一般需要四门基础远支撑,若老师没有教,可以自学一些语言)。
数据结构与算法--堆和堆排序
堆排序是一种原地的、时间复杂度为 O(nlogn) 的排序算法。
堆是一种特殊的树。 只要满足这两点,它就是一个堆:
对于每个节点的值都大于等于子树中每个节点值的堆,我们叫做 “大顶堆” 。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫做 “小顶堆” 。
完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。下标可以直接计算出左右字数的下标。(数组中下标为 i 的节点,左子节点下标为 i?2 ,右子节点下标为 i?2+1,父节点的下标为 i/2? 。)
如果我们把新插入的元素放到堆的最后,你可以看我画的这个图,是不是不符合堆的特性了?于是,我们就需要进行调整,让其重新满足堆的特性,这个过程我们起了一个名字,就叫做 堆化(heapify) 。 堆化实际上有两种,从下往上和从上往下。这里我先讲从下往上的堆化方法。 堆化非常简单,就是顺着节点所在的路径,向上或者向下,对比,然后交换。
我们把最后一个节点放到堆顶,然后利用同样的父子节点对比方法。对于不满足父子节点大小关系的,互换两个节点,并且重复进行这个过程,直到父子节点之间满足大小关系为止。这就是 从上往下的堆化方法 。
一个包含 n 个节点的完全二叉树,树的高度不会超过 log2?n。堆化的过程是顺着节点所在路径比较交换的,所以堆化的时间复杂度跟树的高度成正比,也就是 O(logn)。插入数据和删除堆顶元素的主要逻辑就是堆化,所以,往堆中插入一个元素和删除堆顶元素的时间复杂度都是 O(logn)。
这里我们借助于堆这种数据结构实现的排序算法,就叫做堆排序。这种排序方法的时间复杂度非常稳定,是 O(nlogn),并且它还是原地排序算法。
从后往前处理数组,并且每个数据都是从上往下堆化。 因为叶子节点往下堆化只能自己跟自己比较,所以我们直接从最后一个非叶子节点开始,依次堆化就行了。
建堆的时间复杂度就是 O(n)。 推导过程见 极客时间--数据结构与算法之美
建堆结束之后,数组中的数据已经是按照大顶堆的特性来组织的。数组中的第一个元素就是堆顶,也就是最大的元素。我们把它跟最后一个元素交换,那最大元素就放到了下标为 n 的位置。 这个过程有点类似上面讲的“删除堆顶元素”的操作,当堆顶元素移除之后,我们把下标为 n 的元素放到堆顶,然后再通过堆化的方法,将剩下的 n?1 个元素重新构建成堆。堆化完成之后,我们再取堆顶的元素,放到下标是 n?1 的位置,一直重复这个过程,直到最后堆中只剩下标为 1 的一个元素,排序工作就完成了。
整个堆排序的过程,都只需要极个别临时存储空间,所以堆排序是原地排序算法。堆排序包括建堆和排序两个操作,建堆过程的时间复杂度是 O(n),排序过程的时间复杂度是 O(nlogn),所以,堆排序整体的时间复杂度是 O(nlogn)。 堆排序不是稳定的排序算法,因为在排序的过程,存在将堆的最后一个节点跟堆顶节点互换的操作,所以就有可能改变值相同数据的原始相对顺序。
堆这种数据结构几个非常重要的应用:优先级队列、求 Top K 和求中位数。
假设我们有 100 个小文件,每个文件的大小是 100MB,每个文件中存储的都是有序的字符串。我们希望将这些 100 个小文件合并成一个有序的大文件。这里就会用到优先级队列。 这里就可以用到优先级队列,也可以说是堆。我们将从小文件中取出来的字符串放入到小顶堆中,那堆顶的元素,也就是优先级队列队首的元素,就是最小的字符串。我们将这个字符串放入到大文件中,并将其从堆中删除。然后再从小文件中取出下一个字符串,放入到堆中。循环这个过程,就可以将 100 个小文件中的数据依次放入到大文件中。
我们可以用优先级队列来解决。我们按照任务设定的执行时间,将这些任务存储在优先级队列中,队列首部(也就是小顶堆的堆顶)存储的是最先执行的任务。
如何在一个包含 n 个数据的数组中,查找前 K 大数据呢?我们可以维护一个大小为 K 的小顶堆,顺序遍历数组,从数组中取出数据与堆顶元素比较。如果比堆顶元素大,我们就把堆顶元素删除,并且将这个元素插入到堆中;如果比堆顶元素小,则不做处理,继续遍历数组。这样等数组中的数据都遍历完之后,堆中的数据就是前 K 大数据了。
中位数,顾名思义,就是处在中间位置的那个数。 使用两个堆:一个大顶堆, 一个小顶堆。 小顶堆中的数据都大于大顶堆中的数据。 如果新加入的数据小于等于大顶堆的堆顶元素,我们就将这个新数据插入到大顶堆;否则,我们就将这个新数据插入到小顶堆。 也就是说,如果有 n 个数据,n 是偶数,我们从小到大排序,那前 2n? 个数据存储在大顶堆中,后 2n? 个数据存储在小顶堆中。这样,大顶堆中的堆顶元素就是我们要找的中位数。如果 n 是奇数,情况是类似的,大顶堆就存储 2n?+1 个数据,小顶堆中就存储 2n? 个数据。
极客时间--数据结构与算法之美--28 | 堆和堆排序:为什么说堆排序没有快速排序快?
数据结构与算法分析:C语言描述的书评
现在的程序员总是用着别人封装好的函数、类、库、API,满满的,我们就会觉得编程不过是这么回事,搭积木而已,别人都把材料提供好了,至于材料是怎么做的,不用理会。 真的是这样吗?说数据结构和算法没用的人,那是因为他用不到。为什么用不到?他的层次决定了他不会接触到编程最关键最核心的部分——算法。 先不说那些反应算法的力量的似乎变态的问题,也不说2006年第4期《程序员》的专题,只说,当我们遇到一个问题时,如何搭建数学模型?当我们在有限的硬件条件下要完成高速的数据处理,如何设计?当我们为客户开发完一套软件后,能不能保证未来几年内数据猛增不会带来计算量的指数级增长?当我们需要升级服务器内存和硬盘是,能不能修改几个函数就避免硬件的投资? 这些问题的答案,请在这本书中寻找。 表、栈、队列、树、图等基本数据结构作者并未花大力气描述,而是重在后面的对这些数据结构的应用上,每一个结论都给出了详尽的数学证明,阅读过程中,我们可以感受到蕴含在其中的匠心独运的逻辑思维之美。借用GOOGLE黑板报的一个专题,算法体现了——“数学之美”。 并不是说本书就很完美了,有些章节讲得太过笼统,读起来跳跃感太强,比如第九章的网络流问题,介绍的太过简单,推导过程中省略了不少步骤,对增广路径算法讲的太粗,至于预流推进算法(Push-Relabel)则根本未提,不能不说是一个小小缺憾。
垃圾短信邮件判断算法
垃圾短信,垃圾邮件和推销的电话使我们深受其扰,不过也有些手机软件助手,可以帮助我们垃圾这些垃圾短信和电话,这些软件的背后的算法是什么?
像360手机卫士这种APP在手机本地或云端保存一份电话的手机黑名单数据,来电的时候手机判断下就可以决定是否为骚扰电话了,本地存储,黑名单的数据量如果很大的话,可能会占内存比较大,不过这个可以借鉴以前的布隆过滤器这种数据结构来解决,但是布隆过滤器有误判的可能,有可能来电非黑名单却当成黑名单进行处理了,这对于拦截软件来说是比较严重的问题,所以可能是多种方法来结合判断,或者对于布隆过滤判断是属于黑名单的电话,再通过一次联网到网上的云端再判断一次是否为真正为黑名单用户,不过这就需要联网,还存在延迟的可能;对于布隆过滤器判断为正常用户的,则一定是正常用户,那么大部分时间是不需要联网判断或结合其他办法判断的。
像很多病毒检测软件,或IDS或WAF软件一样,垃圾短信和骚扰电话 也可以建立自己的规则库,通过规则库进行垃圾短信的判断,同样像IDS等软件存在误判的情况一样,垃圾短信采用规则判断的话,也存在一定的误判性,一般也要结合其他的判断规则综合判断。 规则有下面几个:
凡是规则判断,都存在着检测死板,不能检测到不在规则里面的情况,而且会被有心者特意设计避开规则的垃圾短信等。
直观地想一下,垃圾短信,垃圾邮件这些一般都包含特定的词语,或者链接等,那么我们反过来统计邮件中特定的词语的数量,达到一定标准,我们就判断为垃圾邮件。 现在对于这种垃圾邮件的判断问题,一般都通过机器学习来解决,在机器学习的算法中,做垃圾邮件判断这个是属于一个二分类问题,可以用很多中算法来解决,常用的有决策树,贝叶斯,SVM,神经网络等,其中贝叶斯算法是属于一个基于统计学的算法,也是本次要介绍的算法。
贝叶斯算法是为了解决“逆序概率”的问题,举个简单的例子,比如我们袋子中有10个红球,8个白球,然后随机从袋子中拿出一个球,问是红球的概率是多少?这是一个非常简单的概率问题,结果就是10/(10+8),这种正向概率问题比较好理解。那么反过来,如果我们只知道袋子中有红球和白球,但是不知道数量和比例,我们拿了几次球,通过拿出这些球的颜色是否可以推断出袋子中两种球的比例那?
贝叶斯算法中有些根据以前经验总结出来的概率,称为先验概率,可以理解成先前的经验的概率,所以叫先验概率,比如清明时节一般会下雨,下雨的概率大概为70%,这就是通过以前的经验总结的; 后验概率, 是事情发生了,推测可能原因,比如小明迟到了,那么起晚了造成迟到的概率假设为30%,这就是后验概率。条件概率,就是在一个事情假设A发生的情况下,另外一个事情B也发生的概率,记作P(B|A),读作在A发生的情况下,B发生的概率,比如起晚的情况下,小明迟到的概率。 总结一句话:先验概率是经验总结,后验概率是由果推因,条件概率是由因推果。
根据条件概率的定义,可以推导出贝叶斯公式,推导过程在百科里面如下:
说明: 1)P(A|B) = A和B同时发生的概率/B发生的概率,直观想下,B发生的概率一定大于A和B同时发生的概率,相除的含义就是在B发生的概率情况下,有多少A也同时发生的概率,也就符合了条件概率的定义。 2)把除法变乘法就得到了合并后的式子,再变化下,就得到了贝叶斯公式。
可能还比较抽象,举个wiki上的例子:
我们用两种算法进行计算,一是自己直观想,二是用朴素贝叶斯。 假设学校一共有U个人,直观想法计算: P(是女生|穿裤子) = 所有穿裤子的女生数量/所有穿裤子的人数 = U*0.4(女生数量)*0.5(一半穿裤子) / (U*0.4*0.5 +U*0.6*1) = 0.2*U /0.8*U = 25%
如果用朴素贝叶斯算法: P(是女生|穿裤子) = P(穿裤子|是女生) *P(是女生)/P(穿裤子) = 0.5*0.4/[(0.6*1 +0.4*0.5)/1] = 0.2 /0.8 = 25% 说明: P(穿裤子) = 穿裤子人数/总人数= U*0.6*1 + U*0.4*0.5/U = 80% 这样看起来,朴素贝叶斯公式也不是很难。
具体来看下垃圾邮件的分类问题:我们用D表示一封邮件,D是由很多单词组成。用f+表示是垃圾邮件,用f-表示是正常邮件,根据贝叶斯公式,问题形式化:
其中P(f+)和P(f-)比较容易得到,算下一个邮箱里面有多少个是垃圾邮件,多少个是正常邮件即可,不过最好多找几个,算下平均值,这就是所谓的先验概率。 P(D|f+) 表示是垃圾邮件,单词出现的概率,把D展开成N个单词就是: P(d1,d2,d3...dn|f+) 即垃圾邮件中,同时出现这些单词的概率,这个没办法求,假设这些单词之间是独立的,没有什么关联关系,那么P(d1,d2,d3...dn|f+) 就可以扩展为P(d1|f+)* P(d2|f+) P(d3|f+).... P(dn|f+) 这个里面的独立假设,就是朴素贝叶斯的朴素来源,因为不是那么精确,所以叫朴素。计算一个单词在垃圾邮件中出现的概率就比较简单了。
翻译一下: P(垃圾邮件|单词d1,单词d2...单词dn同时出现) =[ P(单词d1,单词d2...同时出现|是垃圾邮件)*P(是垃圾邮件)]/P(单词d1,单词d2...同时出现在一封邮件里面) 根据独立假设: P(垃圾邮件|单词d1,单词d2...单词dn同时出现) =[ P(单词d1出现|是垃圾邮件)*P(单词d2出现|是垃圾邮件)*P(单词d3出现|是垃圾邮件)...*P(是垃圾邮件)]/P(单词d1,单词d2...同时出现在一封邮件里面) 其实我们在判断是否是垃圾邮件的时候,并一定要计算出来P(单词d1,单词d2...同时出现在一封邮件里面),这个也无法精确计算,我们只需要比较垃圾邮件的概率和非垃圾邮件的概率,取大的那一个就可以了,那么久只要计算: P(垃圾邮件|单词d1,单词d2...单词dn同时出现) =[ P(单词d1出现|是垃圾邮件)*P(单词d2出现|是垃圾邮件)*P(单词d3出现|是垃圾邮件)...*P(是垃圾邮件)] P(正常邮件|单词d1,单词d2...单词dn同时出现) =[ P(单词d1出现|是正常邮件)*P(单词d2出现|是正常邮件)*P(单词d3出现|是正常邮件)...*P(是正常邮件)]
1.找到N封邮件,标记好垃圾邮件和非垃圾邮件。 2.对N封邮件进行去掉停词部分,然后采用分词算法做分词。 3.分别计算每个词在垃圾邮件中出现的比例,在正常邮件中出现的比例 4.带入公式算下哪个概率相对大一些,就属于哪个分类。
这里面总结的比较简单,贝叶斯算法,还有很多没有说到,我也理解的不够深刻,先只聊点这种简单的吧,下一篇将找个例子实战下朴素贝叶斯算法。
参考: 1. 数据结构和算法之美:概率统计 2. 数据分析实战:朴素贝叶斯 3. 平凡而又神奇的贝叶斯方法
计算机专业一定要数学特别好吗?
虽然计算机专业需要一定的数学基础,但并不一定要数学特别好。计算机专业中需要掌握的数学知识主要包括:离散数学、概率论、统计学、线性代数、微积分等。这些数学知识不仅仅是计算机专业所需要掌握的,还在其他领域中有广泛应用。因此,如果只是要掌握这些数学知识的基本概念、理论和公式,并不需要数学特别好。当然,如果想在计算机专业中的某些领域发展,如图像处理、密码学、人工智能等,就需要更深入的数学基础。例如,深度学习算法中需要掌握矩阵运算、微积分等高级数学知识,这就需要数学特别好的掌握能力。
总之,虽然数学是计算机专业中必不可少的一部分,但并不是数学特别好才能在计算机领域获得成功。有着好的计算思维能力、良好的团队协作能力和不断学习进步的精神也是很重要的。
计算机专业是当今很热门的专业,对于很多初入该行的人来说,都有一个甚至是固定的错觉,即一定要数学好才能在计算机专业方面取得成功。实际上,这个错觉只是表面现象,尤其是对于在计算机行业初入门的人来说。
计算机工程师的工作本质上是理解计算机科学原理并将其应用于实践,如编写软件、设计算法等等。虽然数学可能会在这些领域的某些方面发挥作用,但它不是作为一种绝对必要的工具之一而存在的,至少对于那些处于初入门状态的工程师来说。
当然,数学知识在许多计算机领域有着广泛的应用。例如,多数机器学习算法与统计学有着密切的关联,而计算机视觉、图像处理等领域中的图形学算法则需要对线性代数、微积分等知识有一定的掌握。如果你的工作与这些特定领域有关,那么数学能力的提升将对你的职业生涯会有很大的帮助。然而,大多数的计算机专业的工作并不需要对数学的专业知识有超出常规学科的掌握。
此外,在计算机领域中,能力的最重要因素并不是你所掌握的科目的数量,而是你的解决问题的能力和如何将他人的意图转化为计算机程序的能力。这些能力来源于不断地学习、思考和实践。事实上,只要有坚定的决心、对计算机充满热情并具有耐心,即使是缺乏数学基础,也可以在计算机领域取得很高的成就。
总之,虽然对于特定领域的专业开发工程师和学术工作者而言,数学能力对计算机工程师的工作具有重要的贡献和价值,但在绝大部分情况下,数学并不被视为影响一个人是否可以在计算机行业中取得成功的重要因素。在计算机行业刚入门阶段,重要的是保持兴趣和热情,保持持续学习,并在学习的道路上不断地提高自身的能力。
考研杂谈,考研过来人和你聊考研。
其实这个问题是仁者见仁智者见智,没有很唯一的答案,完全是看你所研究的计算机哪个方向的。总之就是,计算机专业并不是想象中的那么高不可及,对数学能力要求确实存在,但也并不是特别高要求。但是如果一个学生数学能力很好,那么相应肯定会为他加分很多。
首先我们应该知道计算机科学是计算及其应用的科学和实用方法,它是对结构合理运行正常程序的可行性、结构、表达和机械化的系统研究。小苏接触过许多出自不同专业的学生,在和他们的谈话中总是能够听到一点:我现在只是知道一些理论知识,我需要掌握具体的相关技能才能找到工作。确实,大多数毕业生自从毕业了就没有继续专注于学术界了。因此,我们可以假设大多数读大学读研的人都是为了找份好工作。
其次还应该明确的点就是写代码并不就是计算机科学,懂计算机的一定会写代码,但是会写代码的不一定懂计算机。如果只是想找份写代码的工作,甚至都不需要你去学数学,也不需要你有相应计算机的学位。但是这个事情存在着很明显的局限性,那就是在数学知识很缺乏的背景下你能做的编程工作是非常有限的。
公司的IT部门需要大量程序员来创建自动化或简化业务逻辑的应用程序,这些应用程序是业务线应用程序,可为公司用户提供更有效地完成工作所需的信息。大部分工作围绕大型数据库展开,并将数据集缩减为用户所需的相关信息。
此外涉及机器人和尖端技术的软件开发通常也需要高等数学知识。近几年热门的人工智能、计算机视觉、图像处理、自然语言处理、机器人、通用 GPU 编程、分布式云计算都涉及到许多高等数学知识,而且这些领域每年都在持续快速增长。
如此以来我们可以按照问题要求大概可以分为两类,对数学要求比较高和对数学要求不太作重要求的。对数学要求比较高的方向大致有软件工程,数据库,人工智能,算法,人机交互,信息科学。对数学要求不太作重要求的大致有MIS管理信息系统,计算机图形学/多媒体,系统架构。
但是如果你是属于前者
那么其实这个数学能力要求就比较高了。数学是一门工具性很强的科学,它与别的科学比较起来还具有较高的抽象性等特征。万物皆可用数学语言来描述,更不要说计算机专业,还涉及非常多的计算内容。起初是计算机科学工作者离不开数学,而数学工作者认为计算机对他们可有可无,但是现在是互相都离不开对方了,从每年的超级计算机排行榜一次又一次刷新人们对于计算速度的认知水平就可以明显的知道计算机在数学运算这块的作用与地位不容小觑。
其实出身计算机专业的同学在研究算法的时候,就是在研究数学。算法说白了就是一种更加高效的解决问题的人为创造的思想方法。而思路有了,也就是数学层面有了,必须有一个不耐其烦的计算工具人来孜孜不倦地求解这个问题。而计算机就恰恰好是这个工具人。
而且另外,对于那些在做软件开发的人员来说,数学好肯定是有莫大的优势的。在编程过程中,数学思维清晰,编写出来的程序让人耳目一新。但是很多学生在学生时代写代码的时候,完全没有软件编程的思维,这使得他们的程序很糟,谈不上逻辑存在;而存在这种现象的深层原因则认为是学生对数学思维的不重视,认为编程是编程,数学是数学,我学了这个线代能干嘛?我学这个高数能干嘛?我以后又不去做数学老师,学好这些课并不太大实质帮助。
其实不然,一个理工科学生一定要学好数学,相应的,一个文科生也应该好好了解数学。学计算机的学生之所以觉得《 数据结构 》这门课程很难,就是因为他们的数学思维锻炼的不够!
如果你是属于后者
你选的是计算机专业里面的MIS管理信息系统,计算机图形学/多媒体,系统架构等这些专业的时候,那么这对数学能力要求不是很高。但是这些专业可能对学生的抽象思维能力会有比较高的要求。抽象是这些专业的重要一步。抽象是将复杂的概念简单化。
MIS管理信息系统重在管理,要对海量的数据进行有效地收集、管理、存储。计算机图形学/多媒体通俗地来说,是让一批本来搞文艺创作的人借助计算机软件来创作出新媒体内容,或者也可以换成说是让一批出身理工科的人借助计算机软件来进行作品创作,这个专业重在你的作品好不好看,新不新颖,或者相对上文所述的工作内容,对数学确实没有那么高的要求,有的甚至在大学的学习中,不要求修数学的学分。虽说系统架构里面也涉及了编程,但是我认为系统架构的精髓还是在于他的架构,有一种建设宫殿的美学感在其中,当然这也是仁者见仁智者见智了。
数学是个好东西。对于某些人来说,数学很难,数学也不仅仅是数字,数学是我们大多数学科所建立的逻辑基础。分析、批判性思维和推理只是通过学习和应用数学概念而发展起来的一些抽象技能。为了成为一名优秀的计算机开发人员,这些都是非常重要的必备技能。无论你是在大型公司 IT 部门工作,还是正在开发下一代无线通信网络,数学都是伴随你至始至终的。
大多数人在被提及数学的时候都是首先想到了微积分,然而,计算机涉及到的大部分数学都是关于更抽象的内容,比如离散数学和计算理论等,这些是为大家高质量高水平的工作的奠定基础的基石,同时也是那些选择继续读研究生的学生在读期间需要的掌握的基石。
数学好不是我能进入大厂做程序员的必要条件,但是确是其充分条件,数学对于工程学科来说非常重要,只有在逻辑、批判性思维和抽象数学方面具有扎实的基础,才能用计算机这个工具创造出更大的价值。
计算机专业中对数学的要求是一定的,但不是一定要数学特别好。具体来说:
1. 数学是理解计算机科学的基础:计算机专业包括算法、数据结构、编译器等各种课程,这些课程都建立在一定的数学基础上。而且,计算机科学领域中很多问题都可以用数学方法解决,因此数学能力对于计算机专业学习来说还是很重要的。
2. 数学能力的水平不是唯一评估标准:计算机专业并不是只看数学能力,还有很多其他因素需要考虑,比如编程能力、创新能力、沟通能力等等。因此,即使数学能力不是特别好,如果其他能力还是很强,也是可以成功在计算机专业中发展的。
3. 数学能力可以通过学习和练习提高:很多人并不是天生就擅长数学,数学能力也可以通过不断学习和练习提升。相信自己能够克服数学方面的困难,不断努力,培养自己的数学思维和能力。
综上所述,计算机专业并不要求数学特别好,但是对于理解计算机科学和解决计算机问题还是需要一定的数学能力,同时计算机专业还有很多其他方面的能力需要掌握。需要综合考虑个人兴趣、能力和未来职业规划,选择适合自己的专业方向。
虽然数学在计算机专业中具有重要的地位,但并不是必须要求数学特别好。计算机专业的核心课程往往涉及到高等数学、离散数学、算法与数据结构等数学知识,因此,对一定的数学基础是有一定要求的。但是,首先要明确的是,计算机专业并不等于数学专业,计算机专业的重心更多地在于计算机系统和程序设计等方面,而数学作为其基础学科起到了补充和辅助的作用。
此外,即使数学在计算机专业中非常重要,也并不一定要求在数学方面特别出众。许多计算机科学家和工程师都不是数学天才。在实际工作中,计算机专业人才需要的不仅仅是数学方面的知识,还需要拥有计算机系统和程序设计方面的专业技能和实践经验。因此,对于计算机专业的学生来说,虽然需要在数学学科上投入一定的精力和时间,但更重要的是要全面发展和提高自己的专业素养和技能。
计算机专业不一定要数学特别好,但是数学是计算机专业中的重要基础之一,对于某些领域的研究和开发,数学的理论和方法是必不可少的。本文将从以下几个方面详细分析论证计算机专业与数学的关系,以及数学在计算机专业中的作用:
一、计算机科学基础知识
计算机科学基础知识包括计算机体系结构、操作系统、计算机网络、数据库等方面的知识。虽然这些知识与数学的关系不是很密切,但是计算机科学基础知识的学习和应用需要一定的数学能力。比如,在计算机网络中,需要理解和应用概率论中的随机过程和排队论等知识,以及在计算机安全领域中,需要理解和应用数论中的RSA加密算法等知识。
二、算法和数据结构
算法和数据结构是计算机科学中最基本的概念之一,而它们的设计和分析需要数学的基础知识,如离散数学、图论等。比如,在图像处理领域中,需要用到离散傅里叶变换等数学知识来设计和实现图像处理算法。在机器学习领域中,需要用到线性代数、概率论等数学知识来设计和实现机器学习算法。
三、人工智能和机器学习
人工智能和机器学习是计算机科学中最热门的领域之一,这些领域需要数学中的统计学、概率论、线性代数等知识。比如,在深度学习领域中,需要用到矩阵分解、梯度下降等数学知识来设计和实现深度学习算法。
四、计算机图形学
计算机图形学是计算机专业中的一个分支,涉及到数学中的向量、矩阵、几何等知识。比如,在三维动画制作领域中,需要用到向量、矩阵等数学知识来实现三维动画效果。
五、密码学
密码学是计算机安全领域中的一个分支,需要数学中的数论、代数等知识。比如,在RSA加密算法中,需要用到数论中的欧拉定理、扩展欧几里得算法等知识来实现加密和解密操作。
从以上分析可见,数学在计算机专业中的作用是不可忽视的,但是并不是说一定要数学特别好才能成为一名优秀的计算机专业人才。在实际工作中,需要的是综合素质,包括计算机科学基础知识、算法、数据结构、编程语言等方面的技能,以及创新能力、团队协作能力、沟通能力等综合素质。同时,计算机专业也有很多方向和领域,不同的方向和领域需要不同的技能和知识,因此,数学并不是唯一的关键因素。
举例来说,著名的计算机科学家、图灵奖获得者Donald Knuth在他的《计算机程序设计艺术》一书中,强调了数学在计算机科学中的重要性,但是他也指出,计算机科学家不仅需要数学知识,还需要对计算机科学基础知识和实践应用有深刻的理解和掌握。另外,著名的计算机科学家、微软公司联合创始人比尔·盖茨并没有在大学时学习数学,但他却是一名优秀的计算机专业人才。
综上所述,虽然数学在计算机专业中非常重要,但是并不是说一定要数学特别好才能成为一名优秀的计算机专业人才。计算机专业需要的是综合素质和多方面的技能和知识,而数学只是其中的一部分。如果数学比较好,可以在计算机领域走得更远,做出原创性工作,如果知识讲计算机单做工具那就不需要多高深数学,会编程会用各种工具就行。
java数据结构书籍推荐
咨询热线:13800 VX:wuhanbdqn 魏老师。北大青鸟鲁广校区成立于2006年,目前在校开展课程有网络工程师、软件工程师、UI设计、网络营销培训、大数据培训、云计算培训、WEB前端课程培训、JAVA工程师等课程。
1. 入门级
针对刚入门的同学,建议不要急着去看那些经典书,像《算法导论》、《算法》这些比较经典、权威的书。虽然书很好,但看起来很费劲,如果看不完,效果会很不好。所以建议先看两本入门级的趣味书:
《大话数据结构》
《算法图解》
大话数据结构
将理论讲的很有趣,不枯燥。作者结合生活中的例子去对每个数据结构和算法进行讲解,让人通俗易懂。
算法图解
这是一本像小说一样有趣的算法入门书,书中有大量的图解,通俗易懂。
看完上面一本或两本入门级的书,你就会对数据结构和算法有个大概认识和学习。但这些入门级的书缺少细节、不够系统。所以想要深入的学习数据结构和算法,光看这两本书肯定是不够的。
2. 不同语言的教科书
国内外很多大学都是将《数据结构和算法分析》作为教科书。这本书非常系统、严谨、全面,难度适中,很适合对数据结构和算法有些了解,并且已经掌握了至少一门语言的同学学习。针对不同的语言,分别有:
《数据结构与算法分析:C语言描述》
《数据结构与算法分析:C++描述》
《数据结构与算法分析:java语言描述》
如果你不会C、C++、java,会Python或者JavaScript,可以看:
《数据结构与算法JavaScript描述》
《数据结构与算法:Python语言描述》
3. 面试书籍
现在很多大厂的面试都会考算法题,这里推荐几本面试算法书籍:
《剑指offer》
《编程珠玑》
《编程之美》
剑指offer
为面试算法量身定做的一本书。几乎包含了所有常见的、经典的面试题,如果能搞懂书里面的内容,一般公司的算法面试都应该没问题。
编程珠玑
这本书豆瓣评分有9分,评分很高。这本书最大的特色是讲了很多海量数据的处理技巧。其他算法书籍很少涉及海量数据。
编程之美
有些作者是微软工程师,算法题目较难,比较适合要面试Google、Facebook这样的公司的人去看。
4. 经典书籍
现在数据结构与算法最经典的书籍就是:
《算法导论》
《算法》
《计算机程序设计艺术》
这三本书非常经典,但都很厚,看起来比较费劲,估计很少有人能全部看完。但如果想更深入地学一遍数据结构和算法,还是建议去看看。
算法导论
章节安排不是循序渐进,里面有各种算法正确性、复杂度的证明、推导,对数学功底有一定要求,看起来有些费劲。
算法
偏重讲算法。内容不够全面,对数据结构方面的知识讲的不多,动态规划这么重要的知识点却没有讲。
计算机程序设计艺术
这本书包括很多卷,相比于其他书籍有更好的深度、广度、系统性和全面性。但如果你对数据结构和算法不是特别感兴趣,没有很好的数学、算法、计算机基础,很难把这本书读完、读懂。
5. 课外阅读
有些算法书籍也比较适合在平时悠闲的时候翻翻看看:
《算法帝国》
《数学之美》
《算法之美》
这些书都列举了大量的列子来解释说明,非常通俗易懂。