数据结构
1.基础概念
什么是数据
描述客观事物的符号,是计算机中可以操作的对象,能被计算机识别并且输入给计算机处理的符号集合。包括整型,实型等数值类型,甚至还包括字符,声音,图像视频等飞数据类型。
什么是数据元素
组成数据的有一定意义的基本单位,在计算机中通常作为整体处理,也被称为记录。
例如,在人类中,人就是数据元素;在畜禽类中,鸡、鸭,猪,马,羊等就是其数据元素。
什么是数据项
数据元素的组成单位,一个数据元素可以由若干个数据相组成。数据项是不可分割的最小单位。
例如:人是一个数据元素,其数据项就可以包括眼睛,鼻子,耳朵,联系电话等。
什么是数据对象
数据对象是指性质相同的数据元素的集合,是数据的子集。性质相同指的是数据元素具有相同数量和类型的数据项。
数据,数据元素,数据项之间的关系
2. 什么是数据结构?
数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及他们之间的关系和操作等相关问题的学科。
说人话就是:数据结构就是把数据元素按照一定的关系组成起来的集合,用来组织和存储数据。(相互之间存在一种或多种特定关系的数据元素的集合)
或者还可以这么理解:将数据结构拆开,一方面,数据指的是特定的数据的类型,另一方面,结构指的是特定的存储结构,再将其合起来,就是将指定的数据类型以特定的存储结构存储到内存中。
3. 数据结构分类
3.1 按逻辑结构分类
集合结构
集合结构中中数据元素除了属于同一个集合外,他们之间没有任何其他的关系。如下:
线性结构
线性结构中的数据元素之间存在一对一的关系。
网状结构
网状结构的数据元素时间存在一对多的层次关系。
图形结构
图形结构的数据元素之间是多对多的关系。
3.2 按物理结构分类
顺序存储结构
定义:
简单来说就是**将数据元素存放到地址连续的存储单元里面。**其数据间的逻辑关系和物理关系是一致的,例如常见的数组就是顺序存储结构。
利弊:查找快,增删慢
链式存储结构
定义:
把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的,也可以是不连续的。数据元素的存储关系并不能反映其逻辑关系,因此需要一个指针来存放数据元素的地址。
利弊端:查找慢,增删块
算法
1. 什么是算法?
算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
大白话:一系列问题的解题的步骤。。。
在数据结构的基础上为实现某个功能而执行的相应操作,这个操作叫做算法
2. 算法分析
重点考虑:
(1)花最少的时间完成需求
(2)占用最少的内存空间完成需求
2.1 时间复杂性分析
事后分析估算方法
解:就是用一个“计时器”记录下程序运行所花费的时间,这个计时器是
long start = system.currentTimeMillis();
long end = System.currentTimeMillis();
end - start
就是这个代码所花的时间。
不足:容易受设备影响,例如统一程序在i7的电脑上可能比i5的电脑上运行的更快
事前复杂性分析方法
分析影响因素
(1)算法采用的策略和方案(可人为干预)
(2)编译产生的代码质量
(3)问题的输入规模(可人为干预)
(4)机器执行指令的速度
时间复杂度分析
代码1:
public static void main(String[] args){
int sum = 0;//执行一次
int n = 100;//执行1次
for(int i = 1; i<=n; i++){//执行了n+1次
sum += i;//执行了n次
}
System.out.println("sum = " + sum);
}
//该代码总执行次数是1+1+n+1+n=2n+3次
代码2:
public static void main(String[] args){
int sum = 0;//执行1次
int n = 100;//执行1次
sum = (n+1)*n/2;//执行1次
System.out.println("sum = "+ sum);
}
//总共执行了3次
代码3:
public static void main(String[] args){
int sum = 0;
int n = 100;
for(int i = 1; i<=n; i++){
for(int j = 1; j<=n; j++){
sum += i;//只考虑这一步,它执行了10000次,远大于外面两层循环的100次,所以100次就可以忽略不计
}
}
System.out.println("sum = " + sum);
}
解释:在代码3中,如果要精确地研究循环的条件执行了多少次,是一件很麻烦的事情,所以在研究算法的效率时,只考虑核心代码的执行次数,这样可以简化分析,总之就是不计那些循环索引的递增和循环终止的条件,变量声明,打印结果等操作,主要是把核心操作的次数和输入规模关联起来,输入规模越大,就越只要考虑核心操作的次数。
补充:
- 随着输入规模的增大,算法的常数操作可以忽略不计
- 随着输入规模的增大,与最高次项相乘的常数可以忽略
- 最高次项的指数大的,随着输入规模n的增长,结果也会增长特别快
- 算法函数中n的最高次幂越小,算法效率越高
明确一件事情:执行次数=执行时间
大O表示法
1. 规则
1、用常数1取代运行时间中的所有加法常数
2、在修改后的运行次数中,只保留最高阶项
3、如果最高阶项存在,且常数因子部位1,则去除与这个项相乘的常数
2. 举例
算法一:3次—>O(1)
算法二:n+3次—>O(n)
算法三:n^2+2次—>O(n ^2)
2.2 空间复杂性分析
2.2.1 java中常见内存占用
空间复杂度分析
代码1:
public static int[] reverse1(int[] arr){
int n = arr.length;//申请4个字节大小空间
int temp;//申请4个字节
for(int start = 0,end-n-1; start<=end; start++,end--){
temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
return arr;
}
代码2:
public static int[] reverse2(int[] arr){
int n = arr.length;//申请4个字节
int[] temp = new int[n];//申请n*4个字节,数组自身头信息开销
for(int i = n-1; i>= 0; i--){
temp[n-1-i] = arr[i];
}
return temp;
}
分析:
分析代码1可知:
空间复杂度大小为O(4+4) = O(8),即O(1)
分析代码2可知:
空间复杂度大小为O(4n+24+4) = O(n)
关于复杂度中的24哪来的请看补充5
其他补充
1、计算机访问内存的方式是一次读取一个字节
2、一个引用(机器地址)需要8个字节表示
例如:
Date date = new Date();//date这个变量需要占用8个字节来表示
3、创建一个对象时,比如:new Date(),除了Date对象内部存储的数据(例如年月日等信息)占用的内存,该对象本身也有内存开销,每个对象的自身开销是16个字节,用来保存对象的头信息
4、一般内存的使用,如果不够8个字节,就会被自动填充为8个字节
public static A{
public int a = 1;
}
通过new A()创建一个对象内存占用如下:
(1)整型成员变量a占用4个字节
(2)对象本身占用16个字节
那么创建该对象共需要20个字节,但由于不是8的倍数,会自动填充为24个字节
5、java中数组被限定为对象,他们一般都会因为记录长度而需要额外的内存,一个原始数据类型的数组一般需要24字节的头信息(16个自己的对象开销,4字节用于保存长度以及4个填充字节)再加上保存至所需的内存。
3. 算法特性
输入输出
算法具有零个或多个输入,至少有一个或多个输出。
有穷性
指算法在执行有限的步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成。
确定性
算法的每一步都具有确定的含义,不会出现二义性。算法在一定的条件下,只有一条执行路径,相同的输入只能有为一个输出结果。
可行性
算法的每一步都必须是可行的,也就是说,每一步都能够通过执行有限次数完成。
4. 算法设计要求
正确性
算法的正确性是指算法至少应该具有输入、输出、加工处理无歧义性,能够正确反映问题的需求,能够得到问题的正确答案。
可读性
算法要便于阅读,理解和交流。
健壮性
一个号的算法还应该能够对输入数据不合法的情况做适当的处理。当输入数据不合法时,算法也能做出相关处理,而不是产生异常或莫名其妙的结果。
时间效率高和存储量低
时间效率是指算法的执行时间,存储量低是指算法程序运行时所占用的内存或者外部硬盘存储空间要少。
一个程序的运行时间依赖于算法的好坏和问题的输入规模,而问题的输入规模是指输入量的多少