关于数据结构(内容太多太复杂,后续添加更新)

数据结构

1. 数据结构逻辑图

数据结构
线性结构
非线性结构
一般线性表
特殊线性表
线性表推广
树形结构
网状结构
集合
线性表
栈和队列
数组
广义表
二叉树
有向图
无向图
单列与多列

2. 定义

  • 数据结构
    • 数据结构是指相互之间存在一种或多种特定关系的数据元素的集合,就是描述对象间逻辑关系的学科。
    • 所有的数据结构都支持几个基本操作:读取、插入、删除。
  • 数据存储结构
    • 就是数据在计算机中的存储方式
    • 常用的数据存储方式有两种
      • 顺序存储
        • 把数据存储在一块联系的存储介质(硬盘或内存等)中
        • 例如数组,存储数据时会开辟出一块联系内存,按顺序存储
      • 非顺序存储
        • 与顺序存储相反
        • 例如链表,先不会开辟出一块内存来,而是只需要知道下一个节点存储的位置,就能把所以的数据连起来了。所以单向链表的最后一个节点是指向Null的。
  • 数组、链表、栈和队列是最基本的数据结构,任何程序语言都会涉及到其中的一种或多种

3. 数组

3.1 介绍

  • 概念
    • 存储数据长度固定的容器,存储多个数据的数据类型要一致
  • 原理
    • 数组创建会在内存划分一块连续的内存将数据按照顺序存储
  • 格式
    • 数据类型 [ ] 数组名
    • 数据类型 数组名 [ ]

3.2 初始化

  • 动态初始化
    • 数据类型 [ ] 数组名 = new 数据类型 [数组长度] ;
  • 当动态初始化之后,数组中的每一个数据都拥有一个值。
  • 静态初始化
    • 数据类型[ ] 数组名 = new 数据类型 { 元素1,元素2,……元素n};
  • 简写
    • 数据类型[ ] 数组名 = { 元素1,元素2 …… 元素n };
  • 静态初始化和动态初始化的区别
    • 动态初始化
      • 只明确元素个数,不知道具体的值,推荐动态初始化
      • 只指定长度,并没有给数组里面的每一个元素赋值.
    • 静态初始化
      • 知道具体的元素值,直接静态初始化即可
      • 在指定了长度的同时也给里面的每一个元素都进行了赋值.

3.3 存取

  • 存储
    • 在java中当创建数组时会在内存中划分出一块连续的内存
    • 当有数据进入的时候会将数据按顺序的存储在这块连续的内存中
  • 读取
    • 当需要读取数组中的数据时,提供数组中的索引
    • 数组会根据索引将内存中的数据取出来,返回给读取程序
  • 注意事项
    • 并不是所有的数据都能存储到数组中
    • 相同类型的数据才可以一起存储到数组中
  • 访问
    • 索引
      • 每一个存储到数组的元素,都会自动拥有一个编号,从0开始,这个编号称之为索引,可以通过索引访问到数组中的元素。
    • 访问格式: 数组名 [ 索引 ];
    • 数组访问常见问题
      • 索引越界异常(访问了一个数组没有的索引)
      • 空指针异常 (数组等于null,则数组的内存地址将不再保存,也就意味着数组将不能被操作)

3.4 数组遍历

  • 将数组中的每个元素分别获取出来,就是遍历
  • 数组名.length为数组的存储长度
  • 利用for循环
    • for(int i = 0;i < arr.length; i ++){ }

3.5 特点

  • 读取容易
    • 数组在存储数据时是按顺序存储的
    • 只需要告诉数组索引取数据就可以了
    • 数组会直接把你想要的位置的数据取出来给你
  • 插入和删除困难
    • 这些存储数据的内存是连续的
    • 插入和删除需要变更整个数组中的数据的位置

4. 链表

4.1 链表的存取

  • 存储
    • 分两块区域
    • 一块存储数据
    • 另一块记录下一个数据的地址
  • 读取
    • 从头开始
    • 如果当前不是要找的数据,则根据储存的下一个数据的地址找下一个数据

4.2 特点

  • 读取麻烦
    • 没有索引
    • 只有上一个数据记录下一个数据的地址值
    • 需要遍历查找读取
  • 插入和删除容易
    • 将要插入的数据填入
    • 更改前后数据记录的地址值即可
    • 删除同理
  • 链表的存储方式可以利用到碎片空间

5. 栈

  • 栈是一种先进后出的数据结构
  • 数组和链表都可以生成栈
  • 当数据进入到栈时会按照规则压入到栈的底部
  • 再次进入的数据会压在前次进入的数据上面
  • 在取出栈中的数据的时候会先取出最上面的数据
  • 栈由什么生成,它的操作特点会继承相应的操作特点

6. 队列

  • 队列是一种先进先出的数据结构
  • 数组和链表也都可以生成队列
  • 当数据进入到队列中时也是先进入的在下面后进入的在上面
  • 但是出队列的时候是先从下面出,然后才是上面的数据出
  • 注意:栈和队列是可以互相转换的

7. 树

7.1 概念

  • 树结构是一种包括节点(nodes)和边(edges)的拥有层级关系的一种结构

7.2 树中的相关概念

  • 根节点(root): 树的最上层的节点,任何非空的树都有一个节点
  • 路径(path): 从起始节点到终止节点经历过的边
  • 父亲(parent):除了根节点,每个节点的上一层边连接的节点就是它的父亲(节点)
  • 孩子(children): 每个节点由边指向的下一层节点
  • 兄弟(siblings): 同一个父亲并且处在同一层的节点
  • 叶子节点(leaf node): 没有孩子的节点成为叶子节点
  • 节点: 在树结构中,每一个元素称之为节点
  • 度: 每一个节点的子节点数量称之为度

7.3 二叉树

  • 特点
    • 任意一个节点的度小于等于2
  • 结构图

7.4 二叉查找树

  • 特点
    • 二叉查找树,又称二叉排序树或二叉搜索树
    • 每个节点上最多两个子节点
    • 左子树上的所有节点的值都小于根节点的值
    • 右子树上的所有节点的值都大于根节点的值
  • 添加规则
    • 小的存左边
    • 大的存右边
    • 一样的不存
  • 二叉查找树结构图

7.5 平衡二叉树

  • 特点
    • 二叉树左右两个子树的高度差不超过1
    • 任意节点的左右两个子树都是平衡二叉树
  • 平衡二叉树的旋转
    • 旋转触发时机
      • 当添加一个节点后,该树不再是一个平衡二叉树
    • 左旋
      • 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点让出,给已经降级的根节点当右子节点
    • 右旋
      • 就是将根节点的左侧往右拉,左子节点成了新的父节点,并把多余的右子节点让出,给已经降级的根节点当作左子节点
  • 旋转的四种情况
    • 左左

      • 当根节点左子树的左子树有节点插入导致二叉树不平衡
      • 直接对整体进行右旋即可
    • 左右

      • 当根节点左子树的右子树有节点插入,导致二叉树不平衡
      • 先在左子树对应的节点位置进行左旋,再对整体进行右旋
    • 右右

      • 当根节点右子树的右子树有节点插入,导致二叉树不平衡
      • 直接对整体进行左旋即可
    • 右左

      • 当根节点右子树的左子树有节点插入,导致二叉树不平衡
      • 先在右子树对应的节点位置进行右旋,在对整体进行左旋

7.6 二叉树的遍历

  • 二叉树是一种递归结构
  • 可以直接用递归的方式来遍历它
  • 但是当处理顺序不同的时候,树又分为三种遍历方式
    • 先(根)序遍历: 先处理根,之后是左子树,然后是右子树
    • 中(根)序遍历: 先处理左子树,之后是根,最后是右子树
    • 后(根)序遍历: 先处理左子树,之后是右子树,最后是根

7.7 红黑树

7.7.1 特点
  • 平衡二叉B树
  • 每一个节点可以说红或者黑
  • 红黑树不是高度平衡的,它的平衡通过“自己的红黑规则”进行实现
7.7.2 红黑规则
  1. 每一个节点或是红色的,或是黑色的
  2. 根节点必须是黑色的
  3. 如果一个节点没有子节点或父节点,则该节点的相应属性值为Nil,这些Nil视为叶节点,每个叶节点是黑色的
  4. 如果某一个节点是红色的,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
  5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
7.7.3 红黑树添加节点的默认颜色
  • 添加节点时,默认为红色,效率高
7.7.4 添加节点后如何保持红黑规则
  • 根节点位置
    • 直接变为黑色
  • 非根节点位置
    • 父节点为黑色
      • 不需要任何操作,默认红色即可
    • 父节点为红色
      • 叔叔节点为红色
        • 将父节点设为黑色,将叔叔节点设为黑色
        • 将祖父节点设为红色
        • 如果祖父节点为根节点,则将根节点再次变为黑色
      • 叔叔节点为黑色
        • 将父节点设为黑色
        • 将祖父节点设为红色
        • 以祖父节点为支点进行旋转

8. 哈希表

8.1 哈希值

  • 概念
    • 是根据对象的地址值或者属性值计算出来的一个int 类型的值
  • 使用
    • 哈希表在进行元素存储的时候就需要用到元素的哈希值
  • 获取
    • 可以直接调用Object类中的hashCode方法进行获取
public native int hashCode();  //本地方法,这个方法调用C语言的代码获取对象的哈希值
 如何调用C语言的代码
 JNI  ----> Java Native interface(此方法在本地方法栈中运行)
  • 使用案例
    • HashSet底层的数据结构使用的就是哈希表
  • 特点
    • 同一个对象调用多次hashCode方法获取的哈希值是一样的
    • 不同对象的哈希码值是不一样的,但是我们可以通过重写Object类中的hashCode方法让不同的对象具有相同的哈希码值
      • 一般重写的时候可以借助idea开发工具的快捷方式进行重写

8.2 1.7版本哈希表的数据结构

  • 哈希表 = 数组 + 链表
    • 先创建数组,默认长度为16,默认加载因子为0.75,数组名为table
    • 根据元素哈希值跟数组长度计算出应存入的位置,如果一个位置有多个属性不同的元素,则这些元素组成链表
  • 存储元素的过程
  • 步骤说明
    1. 首先调用对象的hashCode方法获取对象的哈希码值
    2. 然后根据对象的哈希码值计算对象在数组中的存储位置
    3. 然后判断该位置是否存在元素,如果没有将元素存储到该位置
    4. 如果该位置存在元素,则遍历该位置所有元素获取其哈希值和新存入的元素哈希值对比
    5. 如果不相同将元素存储在该位置,原有的元素挂在下面
    6. 如果相同调用对象的equals方法,比较对象的内容是否相同
    7. 如果不相同将元素存在该位置,如果相同则说明重复,不存储

8.3 1.8版本哈希表的数据结构

  • 哈希表 = 数组 + 链表 + 红黑树
    • JDK1.7版本中的哈希表存在弊端
    • 当链表的长度过长会影响插入和查询元素的效率,所以做了优化
    • 当链表的长度超过8并且数组的长度超过64的时候就会把链表变成红黑树
    • 如果数组的长度没有超过64,仅仅会进行扩容
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值