一 . 数据结构
1. 数据
数据:是描述客观事物的符号,是计算机中可以操作的对象,是能够被计算机识别,并输入给计算机处理的符号集合。
但凡能够被计算机储存,识别和计算的东西都叫数据(二进制)
硬盘中:mp3,jgp,doc,avi,exe
内存中:变量,常量,数组,对象,字节码
2.数据元素
数据元素:是组成数据的,有一定意义的基本单位,在计算机中通常作为整体处理,也称为记录。
比如:牛,马,?,鸡等动物就是动物类的数据元素
3.数据项
数据项:一个元素可以由若干个数据项组成。
比如:电脑这样的数据元素,可以有显卡,CPU,内存,主板,显示器,硬盘这些数据项。
数据项是数据不可分割的最小单位。
4.数据对象
数据对象:是性质相同的数据元素的集合,是数据的子集。
性质相同,是指数据元素具有相同数量和类型的数据项,比如:每台电脑都有CPU,内存,主板显示器,显卡,硬盘等相同的数据项
5. 什么是结构
不同数据元素之间不是独立的,而是存在特定的关系,我们将这些关系称之为结构
6. 什么是数据结构?
数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。
数据结构 = 数据 + 数据之间的关系
4. 数据结构主要解决什么样的问题?
在计算机中,数据元素并不是孤立的,杂乱无序的,而是具有内在联系的数据集合,数据结构便是将零散的数据整齐划一
5. 为什么要这么做?
将看似分散的数据以某种方式联系起来可以从中找到一些规律——机器学习
这个世界是有一定归路的,如何找到规律,全靠数据——大数据
6. 在Java中遇到的数据结构
当我们在操作一堆变量的时候,我们会使用数组
数组就是一堆连续的变量,方便对整体进行操作
表示矩阵,我们会使用二维数组
二维数组,就是一个一维数组,只不过每一个元素是另一个一维数组罢了
7. 数据结构的逻辑结构
是指数据元素之间的相互关系,是我们想象出来的,并没有实质性的将其储存在计算机中
集合结构:集合结构中的数据元素除了同属于一个集合外,它们之间没有其他关系
各个元素是平等的,它们的共同属性是”同属于一个集合“
线性结构:线性结构中的数据元素之间是一对一的关系
树形结构:树形结构中的数据元素之间存在一种一对多的层次关系
图形结构:图形结构的数据元素是多对多的关系
8.数据结构的物理结构
物理结构:是指数据的逻辑结构在计算机中的存储形式
顺序存储结构:开辟一组连续的空间储存数据
通常用数组来实现,数组中空间本身是连续的,保证了数据之间的关系
特点:查找快,增删慢
链式存储结构:开辟一组随机的空间存储数据
通常用节点来实现,节点不仅要储存存储数据,还要存储下一个节点的位置以保证数据之间的关系
特点:查找慢,增删快
9.计算机中有哪些数据结构的应用?
手机通讯录
计算机文件系统
函数栈
游戏地图的最短路径
我们需要根据应用场景的不同灵活选择最合适的数据结构
二 . 算法
1.什么是算法?
是解决特点问题求解步骤的描述
在计算机中表现为指令的有序序列并且每条指令表示一个或多个操作,说白了,就是求解一个问题的步骤
例如:求解1+2+3+....+99+100的和:
方案1:
int sum = 0;
int N = 100;
for(int i = 1; i <= N; i++){
sum+=i;
}
方案2:
int N = 100;
int sum = (N + 1) * N / 2;
方案1 随着N的增大,循环的次数也会增大,也就意味着执行的次数和运行的时间也会增大
方案2 随着N的增大,其执行次数只有一次,不会随着N的增大而增大
同一个问题,可以有多种不同的解决方案,也就是说可以用不同的算法去解决同一个问题
2.算法的特性
算法具有五个基本特性:输入,输出,有穷性,确定性和可行性。
-
输入输出:
算法具有零个或多个输入。对于大多数算法来说,输入参数都是必要的,但是对于有些情况,如打印“hello world”这样的代码来说,不需要输入任何参数,因此算法的输入可以是零个。算法至少有一个或多个输出,算法是一定需要输出的,没有输出,算法是没有意义的,输出的形式可以是打印输出,亦可以是返回一个或多个值等
-
有穷性:
有穷性:指算法在执行有限的步骤后,自动结束而不会出现无限循环,并且每一个步骤在可接收的时间内完成。
-
确定性:
确定性:算法的每一步骤都具有确定的含义,不会出现二义性。
算法在一定条件下,只有一条执行路径,相同的输入只能有唯一的输出结果。算法的每个步骤被精确定义而无歧义。
-
可行性:
可行性:算法的每一步都必须是可行的,也就是说,每一步都能够通过执行有限次数完成。
3.算法设计的要求
-
正确性
正确性:算法的正确性是指算法至少应该具有输入,输出和加工处理无歧义性,能正确反映问题的需求,能够得到问题的正确答案。
-
可读性
可读性:算法设计的另一目的就是为了便于阅读,理解和交流。
可读性高有助于人们理解算法,晦涩难懂的算法往往隐含错误,不易被发现,并难于调试和修改
-
健壮性
健壮性:当输入数据不合法时,算法也能做出相关处理,而不是产生异常或莫名其妙的结果
-
时间效率高和存储量低
设计算法应该尽量满足时间效率高和存储量的的需求。
4.如何评价一个算法的好坏?
设计算法要提高程序运算的效率,这里效率大都指算法的执行时间(抛开硬件,语言)
事后统计方法:这种方法主要是通过设计好的程序和数据,利用计算机计时器对不同算法程序的运行时间进行比较,从而确定算法效率的高低
这样会有很多缺陷:
- 必须事先编好程序,在进行运行,如果程序处理的数据量较大,则会花费大量的时间和经历
- 时间的比较主要依赖于计算机硬件和软件环境
- 算法的测试数据设计困难,在数据量较小的时候,不管什么算法其运行时间都是很微小的,相差几乎为零。如果数据量大了,算法的优越性就出来了,但是这样又会耗费时间
事前统计方法:这种方法主要在计算机程序编制前,依赖统计方法对算法进行估算
一个高级程序语言编写的程序在计算机上运行时所消耗的时间取决于下列因素:
- 算法采用的策略,方法
- 编译产生的代码质量
- 问题的输入规模
- 机器执行指令的速度
第一条是算法好坏的根本,第二条要有软件来支持,第四条要看硬件性能,也就是说,抛开这些与计算机硬件,软件有关的因素:
一个程序的运行时间,依赖于算法的好坏和问题的输入规模。所谓问题输入规模是指数据入量的多少
5.算法时间复杂度的定义
- 常数阶O(1),如方案2中的程序,随着n的增加,一次就可以算出结果
- 线性阶O(n)
上述代码执行了2N+3次,时间复杂度O(n)
如果N不断增大,这个常数3就微不足道了,所以可以省去
如果N足够大,这个系数2也可以直接省去,因为,数量级已经是一样的了
忽略常数,忽略N的系数
- 对数阶O(logn)
虽有循环,也随着N的增大而增大,但是这种增大属于加速度减小的的加速运动
int coint = 1;
int N = 100000;
while(count<N){
vount = count*2;
}
假设循环了X次,那么2^X = N,所以X=log2(N)
- 平方阶O(N^2)
int N = 1000;
for(int i = 0; i < n; i++){ //执行N+1次
for(int j = 0; j < n; j++){ //执行N+1次
... //执行N^2次
}
}
时间复杂度计算:
时间复杂度对比:
我们考虑的时间复杂度都是最坏的情况