数据结构:
栈:
特点:先进后出
队列:
特点:先进先出
数组:
数组长度是固定的,存储的元素的数据类型是一致的,并且数组拥有下标索引的概念,方便我们可以通过所以来获取对应位置上的元素。 int[] arr = {}
特点:查询快,增删慢
链表:
由一个链条将多个数据节点连接起来的数据结构叫做链表。
节点:是由数据域和指针域两部分组成。
特点:查询慢,增删快
(如果链表的节点是由一个数据域和两个指针域组成,一个指针域存放前一个节点的地址,一个存放后一个节点的地址,称之为双向链表;
如果把一开始的链表头节点的地址值赋值给最后一个节点的指针域,这样就形成了一个环,这样的链表叫做循环链表)
树:
模仿我们现实生活中的案例生成一个数据结构叫做树,Tree是由根节点和叶子节点组成的。
如果一个数中的节点最多只有两个分支,称之为二叉树。
二叉树的遍历顺序:
前序遍历:根左右,先遍历根,再遍历左,最后遍历右(对每一个二叉树都是如此)。
中序遍历:左根右,先遍左根,再遍历根,最后遍历右(对每一个二叉树都是如此)。
前序遍历:左右根,先遍历左,再遍历右,最后遍历根(对每一个二叉树都是如此)。
自学:1、哈夫曼树(最小生成二叉树)
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffmantree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
2、红黑树(B+Tree\自平衡二叉树)
红黑树性质:1、节点是红色或者黑色
2、根是黑色
3、所有叶子都是黑色
4、如果一个节点是红色的,则它的子节点必须是黑色的
也就是说不可能出现两个连续的红色节点
不过两个连续的黑色节点是可能出现的
5、从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点
哈希表:
是由哈希函数和hashtable组成的,其中哈希函数可以进行自定义。
一般情况下,哈希函数默认是对hashtable的长度做取模运算,计算出数据存储的位置
问题1、案例中,1-9的存储我们能看懂,但是存储10的时候,在下标为0的位置上加1,如果一组数中又出现了一个0,它们将会在一个位置上面出现。这个现象叫做哈希碰撞。
问题2:对于字符串形式的对象,默认是将每一个字符对应的ASCII码值进行相加然后再与hashtable的长度进行取余,计算数据存储的位置。
解决哈希碰撞的方法:
1、给总的ASCII码值打上随机值(目的是让不同的对象存储在不同的位置上)
2、开发地址法(自行了解)
3、拉链法(自行了解)
哈希表用来进行存储数据。在实际开发中哈希表也很少是单独使用的。一般情况下会结合链表一起使用(双链表)
图:是由一组顶点和一组边组成的数据结构。(graph)
顶点:是图的基本单元,也是节点
边:顶点与顶点之间关联关系被称为边
相邻顶点:由一条边连接在一起的顶点
度:一个顶点包含相邻顶点的个数
出度:一个顶点连接别的点的个数
入度:别的点连接该顶点的个数
权重:顶点与顶点连接边上的数值。
遍历图的两个算法: 1、广度优先搜索(BFS)
是一种利用队列实现的搜索算法。常用于找单一的最短路线
2、深度优先搜索(DFS)
是一种利用栈实现的搜索算法。用于找所有解的问题。
它的空间效率高,而且找到的不一定是最优解,必须记录并完成整个搜索,
创建List集合并向集合中添加不同类型的元素
需求:遍历集合,如果集合中存在字符串java,就往集合添加一个新的字符串"spark"
按照我们分析的思路去编写后发现,报错了ConcurrentModificationException,这是为什么呢?
ConcurrentModificationException:并发修改异常
分析原因:因为迭代器是依赖于集合而产生的,我们在做这道题的时候,按照思路获取该集合的迭代器对象
然后去遍历迭代器,但是呢,你在遍历的过程中,还使用了集合本身的方法让集合中的元素发生了改变,但是集合改变了
迭代器它并不知道元素已经发生修改,所以会报错。
如何解决呢?
1、迭代器遍历迭代器修改
2、集合遍历集合修改
使用ArrayList存储自定义对象并遍历
ArrayList底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
使用ArrayList集合存储字符串,并且进行去重(字符串的内容相同)
实现思路:创建一个新的集合,存储去重后的元素
使用ArrayList存储自定义对象并去重(成员变量的值都相同的时候,就重复)
我们按照处理字符串相同的方式来处理相同自定义对象,结果发现并没有进行去重
为什么呢?
想要知道为什么,首先得分析出问题出现在哪一行代码
经过简单的分析后得出,问题出现在if判断中,发现只有当if判断为true的时候,才会将元素添加到集合中。
说明我们这边的判断结果一直是true,去掉!,说明contains()方法的结果一直是false,
怎么去改呢?得先搞明白说明contains方法内部是怎么实现的,所以我们得去看源码。
通过观察源码发现,contains()底层调用得是元素类型中equals方法,而我们自定义类Student类中并没有equals方法
所以调用的是父类Object类中equals方法,而Object类中的equals方法比较的是地址值,又因为每一个学生对象都是new出来的
地址值必然不一样,所以equals比较的结果永远是false,contains比较的结果永远是false,加上!结果永远是true,所以通通
添加到新集合,最终出现没有去重的现象。
怎么解决呢?元素类重写equals()方法
Vector:是List接口下一个具体子类
底层数据结构是数组,查询快,增删慢7
线程安全的,效率低(注意,即使Vector是线程安全的,今后我们也不使用它,后面会学习一个线程安全的类去替代它)
Vector类特有功能
public void addElement(E obj)
public E elementAt(int index)
public Enumeration elements()
LinkedList:底层数据结构是双链表,查询慢,增删快,线程不安全,效率高。
因为LinkedList底层是链表,所以有了头和尾的概念,就多了一些特有的功能
LinkedList类特有功能
添加功能:
public void addFirst(E e)及addLast(E e)
获取功能:
public E getFirst()及getLast()
删除功能:
public E removeFirst()及public E removeLast()
请用LinkedList模拟栈数据结构的集合,并测试
栈的特点:先进后出
题目真正的要求是:自己自定义一个类,底层方法实现是LinkedList,调用的方法名是自己定义,调用自己定义的方法来模拟栈数据结构.
泛型:
在正常写过程中,我们尝试往集合中添加不同类型的数据,在遍历向下转型的时候,会报错,类型转换异常错误
如果有一种办法在我们向集合添加数据的同时,告诉我哪些可以存,哪些不能存,这样的话,我们在写代码的同时就能发现问题并修改
而就不需要在等到运行结果报错后再去修改,这样会很麻烦.
我们之前学过一种容器,在定义的时候,就明确容器中只能存何种数据类型的数据.---数组
int[] arr = new int[3];
arr[0] = 10;
//arr[2] = "hello";
如果集合中有一个办法可以模仿着数组,在定义时候就限定集合只能某种数据类型数据就好了
java替我们考虑到了这一点,提供了一个技术给我们使用,这个技术就叫做泛型.
泛型:泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行。
这样的做法有点像把数据类型当作参数一样进行传递,泛型又称之为参数化类型.
语句定义格式:<引用数据类型>
注意:尖括号中只能存放引用数据类型
泛型的好处:
1、将我们之前运行时候出现的问题,提前到了写代码的时期(编译时期)
2、去除大部分的黄色警告线,使我们的代码更加简洁
3、不用进行强制类型转换了(向下转型)