有两种东西,我对它们的思考越是深沉和持久,它们在我心灵中唤起的惊奇和敬畏就会日新月异,不断增长,这就是我头上的星空和心中的道德律令。”
只有向善 ,我们才可以毫无愧疚地面向老天、仰望星空。
要想成为一个专业的开发人员,至少需要以下三个条件:
- 能够熟练地选择和设计各种数据结构和算法
- 至少要能够熟练地掌握一门程序设计语言
- 熟知所涉及的相关应用领域的知识
后两个条件比较容易实现,而第一个条件则需要花相当的时间和精力才能够达到,它是区分一个程序设计人员水平高低的一个 重要标志,数据结构 贯穿程序设计的始终 ,缺乏数据结构和算法的深厚功底,很难设计出高水平的具有专业水准的应用程序。曾经有一本经典计算机专业书籍叫做《数据结构+算法=程序》,也说明了数据结构和算法的重要性。
计算机专业的学生都开设过数据结构课程,它是计算机学科知识结构的核心和技术体系的基石。数据结构作为计算机专业的专业基础课程,是计算机 考研 的 必考 科目之一,如果有打算报考计算机专业的研究生,这门数据结构你是必须要学好它的,同时,工作以后的同学,会有想去报考计算机 软考 、计算机 等级考试 的,数据结构也是必考的内容之一,科学技术在飞速发展,但是作为基石的科学技术没有动摇,由于近年来算法工程师的高薪火爆,使得数据结构的重视程序空前高涨,总而言之,既然我们已经与计算机接轨就必须 掌握 好它
数据结构:数据库,文件压缩,操作系统,游戏。
数据库:
不管你是从事IT工作的,还是准备从事IT开发的,数据库一定是了解的,我们知道,数据库查询是数据库的最主要功能之一。我们都希望查询数据的速度能尽可能的快,因此数据库系统的设计者会从查询算法的角度进行优化。最基本的查询算法当然是顺序查找(linear search),这种复杂度为 O(n)的算法在数据量很大时显然是糟糕的,好在计算机科学的发展提供了很多更优秀的查找算法,例如 二分查找(binary search)、二叉树查找(binary tree search)等。如果稍微分析一下会发现,每种查找算法都只能应用于特定的数据结构之上,但是数据本身的组织结构不可能完全满足各种数据结构,所以,在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是 索引 ,索引是一种帮助MySQL高效获取数据的 排好序 的 数据结构,其中MySQL使用的数据结构为 B+Tree。
操作系统:
相信现在的我们常用的操作系统大家一定都知道吧,例如:比尔盖茨大叔成立的微软的 Windows操作系统,大神乔布斯苹果的 Mac OS,Java开发常用的 Linux系统,由林纳斯·本纳第克特·托瓦兹开发(百度来的),还有redhat、Solaris、SunCobalt等等,都有使用到数据结构中的,系统栈以及优先队列:堆
文件压缩:
RAR压缩软件、PNG图片、MAP3文件等等,都会使用数据结构,对数据进行压缩(很怕打成了亚索,心虚),而使用压缩的算法是一种树结构叫 哈夫曼树 。
游戏
-
数组:需处理的元素个数确定并且需使用下标时可以考虑,不过建议用泛型List
优点:数组在内存中是连续存储的,索引和修改的速度都非常快
缺点:插入和删除很慢,长度开辟过长易造成内存浪费,长度开辟过短易造成内存越界 -
List: List是泛型的,即List,需处理的元素个数可以不确定,不存在装箱与拆箱,建议多用;而ArrayList:ArrayList list1 = new ArrayList(); ArrayList的元素属于 object 类型存在装箱与拆箱,很损耗性能。,List的底层数据结构就是数组。
-
链表:常用来维护、管理那些需要频繁产生、消除的游戏对象,比如:消除类游戏中需要消除的对象。
-
HashMap:底层是哈希表,是键值对容器,用于处理key/value键值对;底层使用的是数组+链表的结构:Map<String,String> map = new HashMap<>();
-
树: 1.场景管理中的四叉树;2.游戏UI里的菜单一般是分级的,一个主页面可以衍生出很多的子页面的时候,使用树来管理这些菜单是很合适的做法。
-
图: A*寻路算法、DFS、BFS
游戏也是采用了大量的算法,都需要以数据结构为基石,就最简单的功能寻路,鼠标从A点到B点,这个角色就需要寻找一条从A点到B点的路,这条路还需要绕过所有的障碍物,甚至还需要找出最短的路径,这就是最经典的 图论算法,在图论算法种就使用了大量的数据结构。
基本结构:
数组(Array)是一种线性表数据结构,它用一组连续的内存空间来存储一组具有相同类型的数据。
所有的数据结构都支持几个基本操作:读取、插入、删除
为什么数组最大的优点就是能够 快速查询 。因为当我们在读取数据时,只需要告诉数组获取数据的索引位置就可以了,数组就会把对应位置的数据,读取出来
为什么数组最大的优点就是能够 快速查询 。因为当我们在读取数据时,只需要告诉数组获取数据的索引位置就可以了,数组就会把对应位置的数据,读取出来
插入 和 删除 比较困难是因为这些存储数据的内存是连续的,数组大小固定,插入和删除都需要移动元素
五种常见的时间复杂度
O(1):常数复杂度, 最快的算法,数组的存取是O(1)
O(n):线性复杂度, 例如:数组, 以遍历的方式在其中查找元素
O(logN):对数复杂度
O(nlogn):求两个数组的交集, 其中一个是有序数组,A数组每一个元素都要在B数组中进行查找操作,每次查找如果使用二分法则复杂度是 logN
O(n2):平方复杂度,求两个无序数组的交集
在这里,大O描述的是算法的运行时间和输入数据之间的关系
动态数组、栈和队列的讲解,这些底层都是依托静态数组,靠 resize 解决固定容量问题的,之前虽然用户看到的是动态数组,但是依然使用的是静态数组,他是依靠 resize 这个方法解决 固定容量问题 ,但是我们今天要讲解的 链表 不一样,链表 是我们数据结构学习的一个重点,也有可能是一个难点,他是最简单的也是 真正的动态数据结构。
链表
删除操作时间复杂度
|removeList(e) | O(n) |
|removeFirst(e) |O(1)|
|remove(index,e) |O(n/2) = O(n) |
链表 是一种数据结构,在内存中通过 节点记录内存地址 而相互链接形成一条链的储存方式。相比数组而言,链表在内存中不需要连续的区域,只需要每一个节点都能够 记录下一个节点 的 内存地址 ,通过 引用 进行查找,这样的特点也就造就了 链表 增删操作时间消耗很小,而查找遍历时间消耗很大的特点。
我们日常在 Java 中使用的 LinkedList 即为 双向链表。而在链表是由其基本组成单元节点 (Node) 来实现的。我们在日常中见到的链表大部分都是 单链表和双链表
单元节点 (Node):
class Node{
E e;
Node next;
}
e 就是链表元素
next 指的是当前节点的下一个节点
对于 链表 来说它就像我们的火车一样,每一个节点其实就是一节车厢,我们在车厢中存储真正的数据,而车厢和车厢之间还要进行连接,让我们数据是整合在一起的,用户可以方便的在所有的数据上进行查询或其他操作,那么 数据和数据连接 就是由这个 next 来完成的
当然 链表 不能无穷无尽,如果一个节点的 next 是 Null 了,就说明这个节点是最后一个节点了,这就是 链表.
链表的优点:真正的动态,不需要处理固定容量的问题
链表的缺点:丧失了随机访问的能力
什么是栈
栈是一种线性架构
相比数组,栈对应的操作是数组的子集
栈只能从一端添加元素,也只能从一端取出元素,最先放入堆栈中的内容最后被拿出来,最后放入堆栈中的内容最先被拿出来, 被称为 先进后出 、后进先出。
这里说的一端指的就是 栈顶,删除与添加均在栈顶进行操作
新添加的一端为 队尾 ,另一端为 队首 ,当一个元素从队尾进入队列时,一直向队首移动,直到它成为移除的元素为止。这种 先进先出(FIFO) 模式,在我们生活中也随处可见,比如:我们去银行柜台取钱,我们在取钱之前就要先去取号,先做 入队操作,也就是我们队列中的在 队尾添加元素,新来的人等待排队,等待前面的人处理完,当前面取号的人在柜台处理完之后,就会叫下一个号码,这个过程就是 出队操作,只有当在我们前面的人,都处理完之后才会轮到我们。