Java常用数据结构

12 阅读9分钟

百度百科也有相关的介绍 image.png 这里也推荐一些基本经典必读书籍 《大话数据结构》 入门类型的书籍,读起来比较浅显易懂,适合没有数据结构基础或者说数据结构没学好的小伙伴用来入门数据结构。 《数据结构与算法分析:Java 语言描述》 质量很高,介绍了常用的数据结构和算法。

类似的还有  《数据结构与算法分析:C 语言描述》open in new window《数据结构与算法分析:C++ 描述》

视频的话推荐你看浙江大学的国家精品课程— 《数据结构》open in new window 。

姥姥的数据结构讲的非常棒!不过,还是有一些难度的,尤其是课后练习题。

数组

数组(Array  是一种很常见的数据结构。它由相同类型的元素(element)组成,并且是使用一块连续的内存来存储。

我们直接可以利用元素的索引(index)可以计算出该元素对应的存储地址。

相关特点

  1. 有序、相同类型、大小相同的有序集合,长度不能随便改变,从0开始的唯一索引
  2. 存取快;插入删除很慢;
  3. 长度固定,连续的内存空间
假如数组的长度为 n。
访问:O(1//访问特定位置的元素
插入:O(n )//最坏的情况发生在插入发生在数组的首部并需要移动所有元素时
删除:O(n)//最坏的情况发生在删除数组的开头发生并需要移动第一元素后面所有的元素时

链表

链表(LinkedList 虽然是一种线性表,但是并不会按线性的顺序存储数据,使用的不是连续的内存空间来存储数据。

链表的插入和删除操作的复杂度为 O(1) ,只需要知道目标位置元素的上一个元素即可。但是,在查找一个节点或者访问特定位置的节点的时候复杂度为 O(n) 。

使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但链表不会节省空间,相比于数组会占用更多的空间,因为链表中每个节点存放的还有指向其他节点的指针。除此之外,链表不具有数组随机读取的优点。

相关特点

  1. 物理上非连续、非顺序的数据结构,随机存储,由若干node组成
  2. 插入、删除很快,存取比较慢
  3. 长度可以动态变化,非连续的内存空间
  4. 单向链表:data为存储数据,next指向下一个节点,尾节点为空
  5. 双向链表:相比单向链表,多一个prev节点,指向上一个节点,首节点为空
  6. 扩容,只要内存足够,就可以一直新增元素

数组VS链表

  1. ArrayList是基于索引的数据接口,底层是数组,LinkedList是以元素列表的形式存储数据,每个元素都和它前一个和后一个元素连接在一起
  2. 都是线程不安全的,只能单线程下使用,多线程里面可以使用Collections.synchronizedList(List list)来创建
  3. 数据结构不同,Arraylist是动态数组,Linkedlist是链表结构
  4. 效率不同
  • 对随机访问(get/set)ArrayList速度要比Linkedlist快,因为Linkedlist需要移动指针
  • 对新增和删除,Linkedlist要比ArrayList速度快,因为ArrayList需要移动数据,主要是在ArrayList扩容下
  1. 自由性不同
  • ArrayList自由性比较低,因为它需要手动设置固定大小,但使用比较方便,只需要创建,然后添加数据,再通过下标进行使用
  • Linkedlist能够动态的随数据量变化而变化

链表VS二叉树

链表:是一组非连续、非顺序的数据结构,随机存储元素位置关系的内存结构。

二叉树:由结点组成的树状数据结构,每个结点最多可有两个子树(左子节点、右子节点),一般储存有序的元素

执行效率对比

访问元素

  1. 链表:最坏情况是O(n),因为要从头节点依次比较每一个元素,直到找到对应元素
  2. 二叉树:最坏情况是O(log n),因为二叉树创建的时候就对数据进行排序,左子节点小于根节点,根节点小于右子节点,所以搜索数据的时候只要少遍历,也就是log2/n的数据

插入和删除数据:

  1. 链表:插入和删除开销比较小,因为只要改变相关节点的指针
  2. 二叉树:插入和删除开销也比较,也只要改变相关节点的指针

排序:

  • 链表和二叉树:对于大规模的元素序列进行排序,链表和二叉树的表现相似,插入一个元素需要的比较次数与已排序元素的数量按对数关系增加。

空间需求:

  • 二叉树:相比链表,二叉树需要更多的空间来存储,因为它需要额外的空间来存储指针或子节点的信息。

适用场合:

  • 链表:适用于需要频繁插入和删除元素的场合,不可预知元素的数量范围。
  • 二叉树:适用于需要频繁插入、删除和查找元素的场合。

满足以下条件的树: 堆中的每一个节点值都大于等于(或小于等于)子树中所有节点的值。或者说,任意一个节点的值都大于等于(或小于等于)所有子节点的值。

相关特点

  1. 二叉堆,根节点的值最大或最小

栈 (Stack) 只允许在有序的线性数据集合的一端(称为栈顶 top)进行加入数据(push)和移除数据(pop)。因而按照 后进先出(LIFO, Last In First Out) 的原理运作。在栈中,push 和 pop 的操作都发生在栈顶。

栈常用一维数组或链表来实现,用数组实现的栈叫作 顺序栈 ,用链表实现的栈叫作 链式栈

相关特点

  1. 先进后出,后进先出
  2. 入栈即新增一个元素为栈顶
  3. 出栈即将顶元素弹出,前一个元素成新的栈顶

队列

队列(Queue)先进先出 (FIFO,First In, First Out) 的线性表。在具体应用中通常用链表或者数组来实现,用数组实现的队列叫作 顺序队列 ,用链表实现的队列叫作 链式队列队列只允许在后端(rear)进行插入操作也就是入队 enqueue,在前端(front)进行删除操作也就是出队 dequeue

相关特点

  1. 先进先出,后进后出
  2. 入队即把新元素放到队尾
  3. 出队即把队头元素移出队列,队头的后一元素成为队头

树就是一种类似现实生活中的树的数据结构(倒置的树)。任何一棵非空树只有一个根节点。

相关特点

  1. 由n个大于0的有限节点组成层次的关系集合
  2. 每个节点有0个或多个子节点
  3. 没有父节点的节点叫根
  4. 每个非根的节点只有一个父节点
  5. 除根节点外,每个子节点可以分为多个不相交的子树

二叉树

二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。

满二叉树

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是 满二叉树。也就是说,如果一个二叉树的层数为 K,且结点总数是(2^k) -1 ,则它就是 满二叉树

完全二叉树

除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则这个二叉树就是 完全二叉树

平衡二叉树(AVL)

平衡二叉树 是一棵二叉排序树,且具有以下性质:

  1. 可以是一棵空树
  2. 如果不是空树,它的左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树。

红黑树

红黑树(Red Black Tree)是一种自平衡二叉查找树

  1. 根节点是黑色的
  2. 每个节点要么是黑色要么是红色
  3. 每个空的叶子节点都是黑色的
  4. 红黑树中每个节点,从该节点到达其可到达的的叶子节点的路径,都包含相同数量的黑色节点
  5. 如果一个节点是红色,则它的子节点必须是黑色

B树

  1. 每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为null
  2. 任何一个关键字出现且只出现一个节点中
  3. 搜索有可能在非叶子节点结束(最好情况是O(1)就可以找到数据)
  4. 在关键字全集内做一次查找,性能逼近二分查找

B+树

  1. 根节点至少有两个节点
  2. 每个父节点都会出现在子节点中,是节点中的最大或最小的元素
  3. 根节点的最大元素,也是整个b+树的最大元素,以后无论删除插入多少元素都需要保持最大元素在跟节点
  4. 由于父节点元素都出现在子节点中,因此所有叶子节点包含了全量元素信息
  5. 并且每一个叶子节点都带有指向下一个节点的指针,形成一个有序链表
  6. 在b+树中,只有叶子节点带有卫星数据,其他中间节点仅仅是索引,没有任何数据关联
  7. 相比b树,b+树单一节点可以存储更多元素,使io查询次数更少
  8. 自顶向下查询,对于b树查询性能不稳定,最好结果只查询根节点,最坏结果查询到叶子节点,而b+树查询必须查询到叶子节点
  9. 对于范围查询,b+树只需要在链表上做遍历即可

散列表

  1. 键值对直接访问的数据结构

  1. 接触比较少,日常中交通路线图、思维导图都是图的具体体现