导图:
0. 前言:
本章通过介绍常见的数据结构关系以及实现算法的本质,通过大量图文描述加上部分专业术语,旨在揭开数据结构与算法的神秘面纱,期望能为对数据结构与算法处于困惑的读者解惑。
本章图片及代码主要参考于章末的几本书籍(同时推荐大家选择一本去读一下,想要获取电子版的评论区留言)。
目录
1. 什么是数据结构 ?
1.1 基本概念
数据结构是计算机存储、组织数据的方式,是指相互之间存在一种或多种特定关系的数据元素的集合。
先来了解一下几个基本概念:
1.1.1 数据
数据是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。
数据不仅仅包括整型、实型等数值类型,还包括字符 及声音、图像、视频等非数值类型。 比如我们现在常用的搜索引擎,一般会有网页、MP3、图片、视频等分类。
例如Ascll码表:
1.1.2 数据元素
数据元素是组成数据的、有一定意义的基本单位,在计算机中通常作为整体处理。 也被称为记录。 比如,在人类中,什么是数据元素呀?当然是人了。 畜类呢?哈,牛、马、羊、鸡、猪、狗等动物当然就是禽类的数据元素。
1.1.3 数据项
数据项:一个数据元素可以由若干个数据项组成。 比如人这样的数据元素,可以有眼、耳、鼻、嘴、手、脚这些数据项,也可以有姓名、年龄、性别、出生地址、联系电话等数据项,具体有哪些数据项,要视你做的系统来决定。
数据项是数据不可分割的最小单位。在数据结构这门课程中,我们把数据项定义为最小单位,是有助于我们更好地解决问题。 但真正讨论问题时,数据元素才是数据结构中建立数据模型的着眼点。就像我们讨论 一部电影时,是讨论这部电影角色这样的“数据元素”,而不是针对这个角色的姓名或 者年龄这样的“数据项”去研究分析。
1.1.4 数据对象
数据对象:是性质相同的数据元素的集合,是数据的子集。 什么叫性质相同呢,是指数据元素具有相同数量和类型的数据项,比如,还是刚才的 例子,人都有姓名、生日、性别等相同的数据项。 既然数据对象是数据的子集,在实际应用中,处理的数据元素通常具有相同性质,在不产生混淆的情况下,我们都将数据对象简称为数据。
2. 再谈数据结构
数据结构,简单的理解就是关系,比如分子结构,就是说组成分子的原子之间的排列方式。严格点说,结构是指各个组成部分相互搭配和排列的方式。在现实世界中,不同数据元素之间不是独立的,而是存在特定的关系,我们将这些关系称为结构。
那数据结构是什么?数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。 在计算机中,数据元素并不是孤立、杂乱无序的,而是具有内在联系的数据集合。数据元素之间存在的一种或多种特定关系,也就是数据的组织形式。 定义中提到了一种或多种特定关系,具体是什么样的关系,这正是我们下面要讨论的问题
3. 数据之间的关系
在计算机中,数据元素并不是孤立的、杂乱无序的,而是按照一定的内在联系存储起来的,这种数据之间的内在联系就是数据结构的组织形式。
数据与数据的关系(其实是数据元素之间的关系),主要有两种:计算机中实际存储(物理结构)和人为赋予数据的关系(逻辑结构)。(逻辑关系是我们今后最需要关注的问题。)
3.1 逻辑结构(逻辑关系)
3.1.1 集合结构
集合结构:结构中的数据元素除了“同属于一个集合”外,无其他任何关系。
3.1.2 线性结构
线性结构:数据元素之间只存在一对一的关系。(除了第一个元素外,其余元素都有唯一前驱,除了最后一个元素外,其余元素只有唯一后继。)
3.1.3 树形结构
树形结构:数据元素之间存在一种一对多的层次关系。
3.1.4 图形结构(也称网状结构)
图形结构:数据元素是多对多的关系。
3.2物理结构
3.2.1顺序存储
存储顺序是连续的,在内存中用一组地址连续的存储单元依次存储线性表的各个数据元素。顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。
这种存储结构其实很简单,说白了,就是排队占位。大家都按顺序排好,每个人占一 小段空间,大家谁也别插谁的队。我们之前学计算机语言时,数组就是这样的顺序存储结构。当你告诉计算机,你要建立一个有9个整型数据的数组时,计算机就在内存 中找了片空地,按照一个整型所占位置的大小乘以9,开辟一段连续的空间,于是第 一个数组数据就放在第一个位置,第二个数据放在第二个,这样依次摆放。
3.2.2 链式存储
在内存中的存储元素不一定是连续的,用任意地址的存储单元存储元素,元素节点存放数据元素以及通过指针指向相邻元素的地址信息。 链式存储结构:是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。数据元素的存储关系并不能反映其逻辑关系,因此需要用一 个指针存放数据元素的地址,这样通过地址就可以找到相关联数据元素的位置
现在如银行、医院等地方,设置了排队系统,也就是每个人去了,先领一个号,等着 叫号,叫到时去办理业务或看病。在等待的时候,你爱在哪在哪,可以坐着、站着或 者走动,甚至出去逛一圈,只要及时回来就行。你关注的是前一个号有没有被叫到, 叫到了,下一个就轮到了。
3.2.3 索引存储
可以理解成一个黄页,你根据一个人的名字,就可以找到他的电话。所以索引存储又被称为直接寻址。 在存储数据的同时,建立一个附加的索引表,即:
索引存储结构=数据文件+索引表
此外数组也是一个常见的索引存储结构,可以通过下标来直接访问,下标(也就是关键字和地址相关)
3.2.4 散列存储
散列存储,又称hash存储,是一种力图将数据元素的存储位置与关键码之间建立确定对应关系的查找技术。
4. 什么是算法?
4.1 算法概念
算法是为解决一个特定的问题而精心设计的一套数学模型以及在这套数学模型上的一系列操作步骤,这些操作步骤将问题描述的输入数据逐步处理、转换,并最后得到一个确定的结果。(摘自《算法的乐趣》一书)
4.2 算法的性质
- 确定性:算法的每一个步骤都具有确定的含义,不会出现二义性。
- 有穷性:在执行有限的步骤之后,自动结束不会出现无限循环并且每一个步骤在可接受的时间内完成。
- 可行性:算法的每一步都必须是可行的,也就是说,每一步都能够通过执行有限的次数完成。
- 输入:在算法中可以有零个或者多个输入。
- 输出:在算法中至少有一个或者多个输出。
4.3 算法的评判
4.3.1 时间复杂度
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随 n的变化情况并确定T(n)的数量级。
记 作:T(n)=O(f(n))。
它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。 这样用大写O( )来体现算法时间复杂度的记法,我们称之为大O记法。 一般情况下,随着n的增大,T(n)增长最慢的算法为最优算法。
T(n)的量级通常有:
消耗时间从小到大比较:
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
在如今,算法复杂度是我们研究的重点
/*
*整个算法语句频度:2*n*n*n+n*n+n
*T(n)=2*n*n*n+n*n+n 当n趋于无穷大时,T(n)与n*n*n同阶无穷大,
*即T(n)=O(n^3)
*/
void ZAIZAI()
{
int a[n][n];
int b[n][n];
int c[n][n];
int i, j, k;
for (i = 0; i < n; i++) { //语句的频度为n
for (j = 0; j < n; j++) { //语句的频度为n*n
for (k = 0; k < n; k++) { //语句的频度为n*n*n
c[i][j] = b[i][k] + a[k][i];//语句的频度为n*n*n
}
}
}
}
4.3.2 空间复杂度
算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式。
S(n)=O(f(n))
其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。 通常,我们都使用“时间复杂度”来指运行时间的需求,使用“空间复杂度”指空间需求。 当不用限定词地使用“复杂度”时,通常都是指时间复杂度。
我们在写代码时,完全可以用空间来换取时间(时间和空间两者之间平衡),牺牲时间换取空间还是牺牲空间换取时间,其实要看你用在什么地方。
4.4 算法的理解和维护
评估一个算法的优劣不应该只是局限于理论上的时间复杂度和空间复杂度这两个因素,在实际的项目开发中,一个算法是否容易理解往往决定了后期维护的成本,并且容易理解、容易编程的算法往往在调试时也比较容易。
5. 算法与数据结构的联系
5.1 联系
5.1.1 数据结构是实现算法的基础
算法总是要依赖于某种数据结构来实现的。往往是在发展一种算法的时候,构建了适合于这种算法的数据结构。
用一个形象的比喻:图书馆借书的过程,图书馆的图书摆放结构就相当于计算机理解的数据结构,书本就相当于数据元素。从指定位置找到需要的书本,拿到管理员那里借书登记的过程就相当于算法。很明显,只有书本是不够的,还需要人来找到并取走它的算法过程。算法设计必须考虑到数据结构,算法设计是不可能独立于数据结构的。
另外,数据结构的设计和选择需要为算法服务。如果某种数据结构不利于算法实现它将没有太大的实际意义。知道某种数据结构的典型操作才能设计出好的算法。
5.1.2 算法的操作对象是数据结构
算法的设计和选择要同时结合数据结构,简单地说数据结构的设计就是选择储存方式,如确定问题中的信息是用数组存储还是用普通的变量存储或其他更加复杂的数据结构。
算法设计的实质就是对实际问题要处理的数据选择一种恰当的存储结构,并在选定的存储结构上设计一个好的算法。不同的数据结构的设计将导致差异很大的算法。
5.2 区别
- 数据结构关注的是数据的逻辑结构、存储结构以及基本操作。
- 算法更多的是关注如何在数据结构的基础上解决实际问题。
- 算法是编程思想,数据结构则是这些思想的逻辑基础。
6. 总结:
算法的设计同时伴有数据结构的设计,两者都是为最终解决问题服务的。想要设计一款NB的算法,首先得有一款很好支撑它的数据结构。中心思想,先数据结构再算法设计,问题即可迎刃而解。
参考资料:
- 程杰:《大话数据结构》
- 王晓华:《算法的乐趣》
- 严蔚敏、吴伟民:《数据结构(C语言版)》
- 渡部有隆:《挑战程序设计竞赛2》
- 石田保辉:《我的第一本算法书》