一、图 (Graph)

图的基本概念:多对多关系。

图(graph)是一种网状数据结构,图是由非空顶点集合和一个描述顶点间关系的集合组成。图(grapn)是一种网状数据结构,图是田非空顶点集台和一个抽还顶点间天系的集合组成。

在无向图和有向图中V中的元素都称为顶点,而顶点之间的关系却有不同的称谓,即弧或边,为避免麻烦,在不影响理解的前提下,我们统一的将它们称为边(edge)。

无向图实际上也是有向图,是双向图

●加权图:

在实际应用中,图不但需要表示元素之间是否存在某种关系,而且图的边往往与具有一定实际意义的数有关,即每条边都有与它相关的实数,称为权。

这些权值可以表示从一个顶点到另一个顶点的距离或消耗等信息,在本章中假设边的权均为正数。这种边上具有权值的图称为带权图(weighted graph)

●图的存储结构:可以采用顺序存储结构和链式存储结构,更多采用链式存储结构。

●邻接表:链表 链式存储结构

二、集合

集合又称容器。Java中对数据结构(数据存储方式)的具体实现。

可以利用集合存放数据,也可以对集合中的数据进行新增、删除、修改、查看等操作。

集合中数据都是在内存中,当程序关闭或重启后集合中数据会丢失。集合也是一种临时存储数据的容器。

●Collection(集合)接口:

•Queue 接口:队列,先进先出

•List 接口:存储元素有序(插入顺序),可重复

①ArrayList:

底层实现为数组.数组具备的特性ArrayLsit也有,根据存储元素的个数完成数组的扩容。

线程不安全,效率高。

优点:遍历效率高,有随机访问能力,地址连续。

缺点:添加,删除 效率低,将删除元素的后边元素依次向前移动。

②LinkedList

底层实现为链表.链表中默认没有结点,添加数组时,创建结点,将数据存储在结点中。

线程不安全,效率高。

优点:添加,删除 效率高.不需要移动元素,只需要修改地址。

缺点:逼历效率低,丧失随访能力。

③Vector

底层实现为数组.和ArrayList相似,线程安全,效率低。

数组扩容,原数组2倍。

•Set 接口:

①HashSet:

底层实现为HashMap(散列表),HashSet添加时只有一个值,底层向HashMap添加时,将要添加的值放在key中,value的值自动创建(无需关注)。

存储元素,无序,元素不可以重复。

线程不安全,效率高。

②TreeSet

底层实现为TreeMap(红黑树),TreeSet添加时只有一个值,底层向TreeMap添加时,将要添加的值放在key中,value的值自动创建(无需关注)。

存储元素,有序(值大小的顺序),元素不可以重复。

●Map(映射)接口:Map集合

添加数据时为 key valye(键值对),添加时根据key计算出存储的位置,获取时key计算出存储的位置。

•HashMap:

底层实现为散列表

jdk1.8之前:数组+链表

jdk1.8及之后:数组+链表+红黑树

存储数据,无序,不可以重复

线程不安全,效率高

LinkedHashMap:HashMap子类

底层实现为散列表 

jdk1.8之前:数组+链表+ 链表

jdk1.8及之后:数组+链表+红黑树 +链表

后添加的链表保证添加的顺序

•TreeMap:

底层实现为红黑树

存储数据,有序(值大小顺序),不可以重复。

•HashTable:

底层实现为散列表,和HashMap十分相似,

线程安全,效率低

Properties:HashTable子类

存储配置文件中的信息

三、Iterator

中文名称:迭代器。是一个接口,每个集合中实现类都对lterator提供了内部类的实现。

通过lterator可以实现遍历集合的效果。

隐藏集合实现细节,无论是哪种集合都是通过lterator进行操作,而不是直接操作集合。通过一套API实现所有集合的遍历。

可以在遍历时删除集合中的值。

每个实现类都提供了.iterator();返回值就是迭代器对象。

四、Collections

Collections是一个工具类型,一个专门操作集合的工具类。

五、不定项参数 

不定项参数必须在方法定义时,最后一个方法参数。

调用包含不定项参数的方法时,不定项参数位置,可以传递0到任意个指定类型参数。方法内部,把不定项参数当做数组使用即可。

六、哈希表

●引入hash表 

在无序数组中按照内容查找,效率低下,时间复杂度是O(n)

在有序数组中按照内容查找,可以使用折半查找,时间复杂度O(log2n)

●哈希表的结构和特点

hash表 也叫散列表;特点:快。

●哈希表是如何添加数据

①计算哈希码(调用hashCode(),结果是一个int值,整数的哈希码取自身即可)

②计算在哈希表中的存储位置 y=k(x)=x%11

        x:哈希码 k(x) 函数y:在哈希表中的存储位置

●存入哈希表

情况1:一次添加成功

情况2:多次添加成功(出现了冲突,调用equals()和对应链表的元素进行比较,比较到最后,结果都是false,创建新节点,存储数据,并加入链表末尾)

情况3:不添加(出现了冲突,调用equals()和对应链表的元素进行比较,经过一次或者多次比较后,结果是true,表明重复,不添加)

结论1:哈希表添加数据快(3步即可,不考虑冲突)

结论2:唯一、无序。

●如何查询数据

添加数据的过程是相同的

情况1:一次找到23

情况2:多次找到 67

结论:哈希表查询数据快

●hashCode和equals

hashCode():计算哈希码,是一个整数,根据哈希码可以计算出数据在哈希表中的存储位置

equals():添加时出现了冲突,需要通过equals进行比较,判断是否相同;查询时也需要使用equals进行比较,判断是否相同

●各种类型数据的哈希码应该如何获取 hashCode()

•Integer中源码

•Arrays中源码

  如果对象为null,hash码为0.

•String中源码

给定一个内容,对内容进行hash计算,得到一个hash值。只要内容不变,得到的结果一定是不变的。但是不能通过得到的值反向得到原内容。所以hash算法是单向不可逆的算法。

可能出现问题:原内容不一样,经过hash计算后得到的结果一样的,这种情况称为hash碰撞。

String类型中的hashcode()方法。

●解决哈希碰撞的方法

• 链地址法

把Hash表的每个单元作为链表的头节点。当发生冲突时放入到同一个hash值对应的链表。

•开放定址法

发生冲突后寻找下一个hash地址。

•再次哈希法

对hash值再次进行hash计算

•建立公共溢出区

把hash表分为基本表和溢出表。当溢出时放入到溢出表中。

•装填因子/加载因子/负载因子

哈希表的长度和表中的记录数的比例-装填因子:

在实际情况中,一般需要根据最终记录存储个数和关键字的分布特点来确定Hash表的大小。另一种情况是可能事先不知道最终需要存储的记录个数,则需要动态维护Hash表的容量,此时可能需要重新计算Hash地址。

负载因子=表中的记录数/哈希表的长度,

如果装填因子越小,表明表中还有很多的空单元,则添加发生冲突的可能性越小;而装填因子越大,则发生冲突的可能性就越大,在查找时所耗费的时间就越多。

一般情况下,装填因子取经验值0.5。

●类没有重写Object中的hashCode()方法,调用Object中的hashCode()方法,根据引用类型在内存中的地址计算hashCode

重写了hashCode()方法,根据存储的值进行计算

•equals()方法:返回boolean

没有重写,使用Object中的equals()方法,比较       地址。

重写,使用重写后的equals()方法,比较   值。

•hashCode()方法;返回hash码

没有重写,使用Object中的hashCode()方法,根据内存中的地址计算 hash码

重写,使用hashCode()方法,根据存储的值计算 hash码

•equals()方法执行过后相同,hash码是否相同?

           equals()方法执行过后相同     值相同

          值相同,hash码相同

七、HashMap底层源码分析(JDK1.7及以前)

DK1.7及其之前,HashMap底层是一个table数组+链表实现的哈希表存储结构,使用头插。

链表的每个节点就是一个Entry,其中包括:键key、值value、键的哈希码hash、执行下一个节点的引用next四部分。

●put()方法

调用put方法添加键值对。哈希奉三步添加数据原理的具体实现;是计算key的哈希码,和value无关。

注:

•计算哈希码时,不仅调用了key的hashCode(),还进行了更复杂处理,目的是尽量保证不同的key尽量得到不同的哈希码

•根据哈希码计算存储位置时,使用了位运算提高效率。同时也要求主数组长度必须是2的幕)

•添加Entry时添加到链表的第一个位置,而不是链表末尾

•添加Entry是发现了相同的key已经存在,就使用新的value替代旧的value,并且返回旧的value

●addEntry()方法

添加元素时如达到了國值,需扩容,每次扩容为原来主数组容量的2倍

●get()方法 java

调用get方法根据key获取value。

哈希表三步查询数据原理的具体实现

其实是根据key找Entry,再从Entry中获取value即可。

●HashMap底层原理

•从ava8开始HashMap底层由数组+链表+红黑树。

•使用HashMap时,当使用无参构造方法实例化时,设置扩容因子为默认扩容因子0.75。

•当向HashMap添加内容时,会对Key做Hash计算,把得到的Hash值和数组长度-1按位与,计算出存储的位置。如果数组中该没有内容,直接存入数组中(Node节点对象),该下标中有Node对象了,把内容添加到对应的链表或红黑树中。

•如果添加后链表长度大于等于8,会判断数组的长度是否大于等于64,如果小于64对数组扩容,扩容长度为原长度的2倍,扩容后把原Hash表内容重新放入到新的Hash表中。如果Hash长度大于等于64会把链表转换红黑树。

•最终判断HashMap中元素个数是否已经达到扩容值(threshold),如果达到扩容值,需要进行扩容,扩容一倍。反之,如果删除元素后,红黑树的元素个数小于等于6,由红黑树转换为链表。

●TreeMap:底层为红黑树

①根节点颜色为黑色

②红色结点下不能有红色结点

      红色结点下可以有黑色结点

      黑色结点下可以有红色结点

      黑色结点下可以有黑色结点

③从一个结点触发,到其子节点经过的黑色结点数相同

④左边为父节点小,右边比父节点大

⑤没有追求绝对平衡,最多3次旋转可以完成平衡

八、File类

java.io.File类,这个类对应的是操作系统中的一个文件或一个文件夹(目录)。

通过File类可以实现操作系统中文件|文件夹的创建、删除、查看、重命名等操作。

●路径

File类操作资源时有两种路径写法:

①全路径。即:从磁盘名称开始的路径。

②项目路径。即:从项目跟目录开始的路径。

在windows中,文件路径都是通过右斜杠\表示子目录。

在Java中如果字符串的值中出现右斜线表示转义字符。会对后面的一个字符进行转义。所以在Java中如果想要表示上面的路径可以使用两个右斜线或一个左斜线。

对应windows中D:\soft\jdk的路径,在Java中路径的字符串写法为

String path ="D:\\soft\\jdk";

String path2 ="D:/soft/jdk";

●File类构造方法

•构造方法

①Constructor and Description

File(File parent, String child)

创建从一个家长的抽象路径名和一个孩子的路径字符串的新File实例。

②File(String pathname)

通过将给定的路径名的字符串转换成一个抽象路径名创建一个新的 File实例。

③File(String parent, String child)

创建从父路径名的字符串和一个孩子的一个新的 File实例文件。

④File(URI uri)

通过将给定的 file:URI到一个抽象路径名创建一个新的 File实例。

•File一共提供了四个构造方法,都是有参构造,并没有提供我们能使用的无参构造。其中我们比较常用的是File(String)和File(String,String)和File(File,String)

①File(String):参数表示文件或文件夹全路径。

②File(String,String):中第一个参数表示父文件夹路径,第二个参数表示资源路径。

③File(File,String):第一个参数表示父文件夹对象,第二个参数表示资源路径。

●创建文件夹

File中有两个方法能够创建文件夹。

mkDir():创建路径中最后一层文件夹。如果希望创建的文件夹已经存在或路径中前面文件夹不存在,返回false。

mkDirs():创建文件夹,如果路径中的文件夹不存在,先创建路径中的文件夹,然后再创建指定的文件夹。返回值表示是否创建成功。

●判断资源是否存在

exists():判断资源是否存在。存在返回true,不存在返回false。

●创建空文件

createNewFile()方法可以创建一个空文件,要求文件所在目录必须真实存在。

JDK在定义这个方法时抛出了IOException(Checked异常),文件路径不正确、无法操作文件等情况下抛出此异常。返回值表示是否创建成功。

●重命名文件

renameTo(File)剪切。利用剪切特性,把资源剪切后放入到原路径中,起新名字,实现重命名功能。

●删除文件

delete()可以实现删除文件。如果文件成功删除返回true。如果文件不存在或删除失败返回false。

●判断资源是否为文件

isFile()判断资源是否是文件。如果是文件返回true,如果是文件夹或不存在这个资源返回false。

●查看文件名和文件路径

getName()文件名。

getAbsolutePath()文件在磁盘中全路径。

getPath()创建文件时指定的路径。

●查看目录中内容

list()返回值为目录中资源的名称。返回值类型String,。数组长度和资源个数相同。如果是空文件夹范围一个长度为0的数组对象。如果文件夹不存在返回null。

listFiles()返回值为目录中资源对象。返回值类型File,。数组长度和资源个数相同。如果是空文件夹范围一个长度为0的数组对象。如果文件夹不存在返回null。

九、IO流

流就是将数据无结构化的传递。强调的是数据的传输过程。

流分为输入流(Input)和输出流(Output),简称为1/0流。输入流表示从一个源读取数据,输出流表示向一个目标写数据。

Java中1/0操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。

•输入流:从磁盘读到内存中

        硬盘 输入Input 内存

•输出流:从内存写到磁盘中

       内存 输出output 硬盘

•流是一个抽象概念。流是看不见的。

•流有出发点和目的地。相对出发点来说就是输出流,相对目的地来说就是输入流。

•流是数据运输的载体。

●Java中IO流分类

在JDK中提供了10类的支持。这些类都在java.io包中。

①根据方向的划分:输入流和输出流

②根据数据的单位划分:字节流和字符流。

③根据功能的划分:节点流和处理流(缓冲流)

字节流就是流中数据以字节为单位(byte)。特别适用于音频、视频、图片等二进制文件的输入、输出操作。字符流就是流中数据以字符为单位。存在的意义:高效、方便的读取文本数据。