数据结构


本文所有代码及笔记已上传至GitHub:https://github.com/yan7Cara/DataStructure

一.复杂度

1.时间复杂度:估算程序指令的执行次数(执行时间)
2.空间复杂度:估算所需占用的存储空间
3.一般用大O来描述复杂度 他表示的是数据规模n对应的复杂度 忽略常数 低阶 系数 对数阶一般忽略底数
4.在这里插入图片描述

二.动态数组ArrayList

1.数据结构是计算机存储、组织数据的方式 一般有:线性结构(线性表 数组 链表 栈 堆队列 哈希表/散列表)树型结构(并查集 哈弗曼树 trie 堆 B树 红黑树 AVL树 二叉树) 图形结构(邻接表 邻接矩阵)
2.线性表:具有n个相同类型元素的有限序列(n>=0)
3.数组是一种顺序存储的线性表 所有元素的内存地址是连续的
4.数组的缺点:无法动态修改容量 于是有了动态数组
5.动态数组的成员变量会自动初始化 int类型自动初始化为0 对象类型自动初始化为null
6.动态数组的缺点:可能会造成内存空间的大量浪费(?因为他可以自动扩容 缩容 也许他扩容后压根用不到扩容的那么多?)
7.动态数组的扩容 缩容 见IDEA
(1)扩容:只要扩容的倍数乘以缩容的时机不为1 则可避免复杂度震荡
扩容因子(扩容的倍数):1.5
扩容原理:创建一个新的数组 容量为旧数组的1.5倍 然后将旧数组的元素依次放在新数组中
(2)缩容:缩容时机:1/2
缩容原理:创建一个新的数组 容量为旧数组的0.5倍 然后将旧数组的元素依次放在新数组中

三.链表Linkedlist

1.链表可以用到多少内存就申请多少内存
2.链表:链式存储的线性表 所有元素的内存地址不一定连续
3.单向链表中的每一个节点中存放:本节点的内容 下一个节点的地址
4.虚拟头结点:不存储数据 仅仅为了统一处理节点
5.双向链表中的每一个节点中存放:本节点的内容 下一个节点的地址 上一个节点的地址
6.双向链表比单向链表的操作数量缩小了一半
7.动态数组和双向链表的比较:
(1)动态数组:开辟、销毁内存空间的次数相对较少,但可能造成内存空间浪费(可以通过缩容解决)
(2)双向链表:开辟、销毁内存空间的次数相对较多,但不会造成内存空间的浪费

8.单向循环链表:每一个节点中存放:本节点的内容 下一个节点的地址 但最后一个节点中存储的下一个节点的地址不是null 而是第一个节点的位置
9.双向循环链表:每一个节点中存放:本节点的内容 下一个节点的地址 上一个节点的地址 但第一个节点存储的上一个节点的地址不是null 而是最后一个节点的地址 最后一个节点中存储的下一个节点的地址不是null 而是第一个节点的位置
10.循环链表:约瑟夫问题
11.静态链表:用数组来实现链表

四.栈

1.入栈 出栈 后进先出 只能在一端进行操作
在这里插入图片描述

2.可通过动态数组 链表来实现栈
3.栈的应用:浏览器的前进后退 软件的撤销 恢复

五.队列

1.队尾添加(入队) 队头移除(出队) 只能在两端进行操作 先进先出
在这里插入图片描述

2.双向链表实现队列 也可以用动态数组 链表
3.双端队列:能在头尾两端进行添加 删除
4.循环队列:用动态数组实现的队列
5.循环双端队列:可以进行两端添加 删除操作的循环队列
以上两种队列中计算真实索引的方法

六.树

1.节点的度:子树的个数
2.树的度:所有节点度中的最大值
3.节点的深度:从根节点到当前节点的唯一路径上的节点总数
4.节点的高度:从当前节点到最远叶子节点的路径上的节点总数
5.树的深度:所有节点深度中的最大值
6.树的高度:所有节点高度中的最大值
7.树的深度=树的高度
8.有序树:树中任意节点的子节点之间有顺序关系
9.树中任意节点的子节点之间没有顺序关系 也称自由树
10在这里插入图片描述

11.二叉树的性质
在这里插入图片描述

12.在这里插入图片描述

13.在这里插入图片描述

14.在这里插入图片描述

15.在这里插入图片描述

16.在这里插入图片描述

17.在这里插入图片描述

七.二叉搜索树BST

1.在 n 个动态的整数中搜索某个整数?(查看其是否存在)使用二叉搜索树,添加、删除、搜索的最坏时间复杂度均可优化至:O(logn)
2.二叉搜索树又称二叉查找树 二叉排序树 是二叉树的一种
3.任意一个节点的值都大于其左子树所有节点的值
4.任意一个节点的值都小于其右子树所有节点的值
5.左右子树也是一棵二叉搜索树
6.二叉搜索树存储的元素必须具备可比较性 不允许元素为null
7.添加(若这个节点已经存在 则覆盖它的值):找到父节点 查看添加到父节点的哪个位置
8.删除:
(1)若节点为叶子节点:判断该叶子节点是其父节点的左子节点还是右子节点 然后让其父节点的左/右子节点置空 若该叶子节点的父节点为null 则表明该树只有这一个节点 删除节点就是将root置空
(2)若节点度为1 即只有一个子节点:判断该节点是其父节点的左子节点还是右子节点
判断该节点的着唯一一个子节点是自己的左子节点还是右子节点
然后用子节点代替原节点的位置 即该节点的父节点的左/右子节点=该节点的子节点的左/右子节点
该节点的子节点的左/右子节点的父节点=该节点的父节点的左/右子节点 若该节点是根节点 即该节点的父节点为null
那么root=该节点的左/右子节点 该节点的左/右子节点的父节点=null
(3)若节点度为2 即有左右两个子节点:先用该节点的前驱/后继节点的值覆盖该节点的值 然后删除相应的前驱/后继节点
若一个节点的度为2 那么他的前驱/后继节点的度只能为1或0
9.找前驱节点:前驱节点:中序遍历时的前一个节点
(1)有左子节点:那么左子节点的最后一个右子节点(此时遍历完左子节点)就是该点的前驱节点
(2)没有左子节点:该节点的前驱节点一定是他的父节点或祖父节点 但是可能他在他的父节点的左边 那他的父节点肯定不是他的前驱节点 因为要先遍历该节点再遍历该节点的根节点(这里也就是他的父节点)所以该节点的前驱节点可能是他的祖父节点 但是可能他的父节点还是他的祖父节点的左子节点 由于要先遍历完该节点的左子节点才遍历该子节点 所以要找他的父节点是他的祖父节点的右子节点 从父节点 祖父节点中寻找前驱节点
10.找后继节点:前驱节点:中序遍历时的后一个节点 思想同找前驱节点 想不到就看ppt

八.二叉树

1.二叉树的遍历:
(1)前序遍历:树状结构展示(注意左右子树的顺序)
(2)后序遍历:先子后父的操作
(3)中序遍历:二叉搜索树的中序遍历按升序或者降序处理节点
(3)层序遍历(必须背下来):计算二叉树的高度 判断一棵树是否为完全二叉树
实现思路:使用队列
1.将根节点入队
1.循环执行以下操作 直到队列为空
(1)将队头节点A出队 进行访问
(2)将A的左子节点入队
(3)将A的右子节点入队
按照上述步骤:最初root入队 此时队列只有root 不为空 将root出队进行操作 然后将root的左子节点A入队 将root的右子节点B入队
此时队列不为空 队头A出队 进行操作 将A的左子节点C入队 将A的右子节点D入队 队列不为空 队头B出队 进行操作
将B的左子节点E入队 将A的右子节点F入队 此时队列不为空 有CDEF 如此循环遍历
2.计算二叉树的高度:根节点入队 队列不为空 队列弹出根节点 本层元素数量-1 队列空 根节点的左节点入队 根节点的右节点入队 由于此时levelSize=0 意味着要访问下一层 将队列的长度赋值给levelSize 并且高度+1 因为队列不为空 所以弹出根节点的左节点 levelSize-1 根节点的左节点的左节点入队 根节点的左节点的右节点入队 此时levelSize不为0且队列不为空 弹出根节点的右节点 levelSize-1 此时levelSize=0 根节点的右节点的左节点入队 根节点的右节点的右节点入队 此时levelSize为0 意味着要访问下一层 将队列的长度赋值给levelSize 并且高度+1 如此循环 最后返回height
3.判断是否为完全二叉树:根节点入队 队列不为空 leaf=false 若根节点的左子节点不为空 则入队 若根节点的左子节点为空 右子节点不为空 则不是完全二叉树 若根节点的右子节点不为空 则入队:
(1)若根节点的右子节点为空 则leaf=true 根节点的左子节点出队 因为完全二叉树的叶子节点只会出现在最后两层 所以此时根节点的左子节点必须是叶子节点 才是完全二叉树 因为leaf=true就代表了上一个节点(此处为根节点)的右子节点为空 即叶子节点 若此时根节点的左子节点不是叶子节点 则不是完全二叉树
(2)若根节点的右子节点不为空 则继续循环遍历
4.后/前+中 可以构造出唯一的一棵二叉树
若是真二叉树 前+后 可以构造出唯一的一棵二叉树 否则不唯一

九.平衡二叉搜索树BBST

1.如果从小到大添加节点 那么可能出现树失衡 退化成链表 删除节点也可能会导致失衡
在这里插入图片描述

所以,在节点的添加、删除操作之后,想办法让二叉搜索树恢复平衡(减小树的高度)。最理想的平衡就是像完全二叉树、满二叉树那样,高度最小。我们并不一定要树达到最理想的平衡状态 因为这样付出的代价太大 我们只要用尽量少的调整次数达到适度平衡即可 一棵达到适度平衡的树称为平衡二叉树BBST
2.常见的BBST:AVL树 红黑树
在这里插入图片描述

十.AVL树

1.最早的自平衡二叉搜索树
2.在这里插入图片描述

3.在这里插入图片描述

4.解决失衡:旋转

十一.B树

1.平衡的多路搜索树,多用于文件系统、数据库的实现
2.B树的性质
(1)1 个节点可以存储超过 2 个元素、可以拥有超过两个子节点
(2)平衡,每个节点的所有子树高度一致
3.在这里插入图片描述

4.在这里插入图片描述

5.搜索
在这里插入图片描述

6.添加(可能产生上溢)
新添加的元素必定是添加到叶子节点
上溢:添加后节点数量超过限制 m阶B树非根节点存储元素的个数范围:m/2-1<=x<=m-1 所以非根节点产生上溢时 节点个数必为m 上图为4阶B树 若加入51 则会产生上溢
7.处理上溢
在这里插入图片描述
在这里插入图片描述

8.删除(可能产生下溢)
真正的删除元素都发生在叶子节点中
删除的情况:
(1)假如需要删除的元素在叶子节点中
(2)
在这里插入图片描述
在这里插入图片描述

下溢:叶子节点被删除后可能会导致节点的数量低于最低限制m/2-1 下溢节点的元素数量必然等于m/2-2
9.处理下溢
(1)在这里插入图片描述

(2)在这里插入图片描述

十二.红黑树

1.在这里插入图片描述

这五条性质可以保证红黑树等价位4阶B树 所以红黑树是平衡的
2.在这里插入图片描述

3.添加:
添加的所有情况:
1.若parent是black 不用操作 直接返回
2.若parent是red 添加后有两种情况:(1)添加后不会溢出(2)添加后会溢出
判定这两种情况的条件是:添加的节点的uncle节点是不是red 若不是则不溢出 若是则溢出
(1)添加后不会溢出 即添加的节点的uncle节点不是red
parent染成BLACK,grand染成red 此时若为LL:grand进行右旋 若为RR:grand进行左旋 若为LR:parent左旋 grand右旋
若为RL:parent右旋 grand左旋
(2)添加后会溢出 即添加的节点的uncle节点是red
parent、uncle 染成BLACK grand染成RED,向上合并 当成新添加的节点进行处理
4.删除:B树中 真正的删除元素都发生在叶子节点中
删除的所有情况:
1.若删除的节点是red 直接删除
2.若删除的节点是black:
(1)拥有2个RED子节点的BLACK节点:会找到他的子节点(前驱/后继节点)覆盖他 然后删除子节点(前驱/后继)
子节点肯定是red 直接用第一种情况来处理
(2)拥有1个RED子节点的BLACK节点:判定条件:用以替代的子节点是red。删除black节点 将替代的子节点染成black
(3)black叶子节点:删除后可能会导致下溢 也可能不会导致下溢
a.兄弟节点为black 且兄弟节点至少有一个RED子节点
删出后进行旋转 若为LL:兄弟节点的子节点进行右旋 若为RR:兄弟节点的子节点进行左旋 若可能为RR或RL 则选择RR
对兄弟节点的子节点进行左旋 若可能为LL或LR 则选择LL 对兄弟节点的子节点进行右旋
旋转之后的中心节点继承他的父节点的颜色 旋转之后的左右子节点染为black
b.兄弟节点为black 且兄弟节点没有RED子节点:删除后兄弟节点染red 父节点染black
(2)兄弟节点为red:兄弟节点染black 父节点染red 进行旋转 于是又回到兄弟节点是black的情况 按上述处理
5.在这里插入图片描述

6.红黑树的添加默认会查重 去除重复

十三.集合Set

1.集合:不存放重复元素 常用于去重
2.可用动态数组 链表 二叉搜索树(AVL树 红黑树)实现 listSet treeSet

十四.映射Map/字典

1.key唯一
2.可用链表 二叉搜索树(AVL树 红黑树)实现 treeMap treeMap添加 删除 搜索的平均时间复杂度都是O(n) 若用hash表来实现map 则添加 删除 搜索的平均时间复杂度都可以优化到O(1)
3.Map 的所有 key 组合在一起,其实就是一个set 因此 set可以间接利用map来做内部实现

十五.Hash表

1.hash表也叫散列表
2.空间换时间的典型应用
3.哈希函数也叫散列函数
4.哈希表内部的数组元素叫桶 整个数组叫桶数组
5.哈希冲突也叫哈希碰撞:两个不同的key经hash函数计算出相同的结果
在这里插入图片描述

6.在这里插入图片描述

7.在这里插入图片描述

8.如何生成key的hash值:尽量让每个hash值唯一 尽量让key的所有信息参与运算
(1)key为整数:hash值就是他本身
(2)key为浮点数:浮点数转为整数 hash值就是这个整数
(3)key为long:高32位^(异或)低32位=32位的hash值
(4)key为double:double转long 然后高32位^(异或)低32位=32位的hash值
(5)key为字符串:在这里插入图片描述

素数和其他数相乘的结果比其他方式更容易产生唯一性 减少hash冲突
(6)key为自定义对象:上一个数据的hashcode*31+下一个数据的hashcode 拼接在一起形成最终的hashcode
9.hashMap的key必须实现hashCode equals方法 允许key为null 自定义对象必须自己实现hashCode equals方法 允许key为null
10.实现equals方法
在这里插入图片描述
11.在这里插入图片描述
12.在这里插入图片描述

13.在这里插入图片描述
14.treeMap VS HashMap
在这里插入图片描述
15.LinkedHashMap:在HashMap的基础上维护元素的添加顺序 使得遍历的结果是遵从添加顺序的
16.HashMap底层由红黑树实现

十六.二叉堆

1.在这里插入图片描述

2.应用:从海量数据中找出前K个数据 使用堆
3.在这里插入图片描述

4.在这里插入图片描述

5.最大堆添加:在这里插入图片描述
在这里插入图片描述

6.最大堆删除(下滤)在这里插入图片描述
7.批量建(最大)堆:自上而下的上滤 自下而上的下滤
在这里插入图片描述
在这里插入图片描述
8.在这里插入图片描述

十七.优先级队列

优先级队列:普通的队列是先进先出 优先级队列则是按照优先级高低进行出队 比如将优先级最高的元素作为队头优先出队
优先级队列的实现:二插堆 把优先级最高/最低的元素放在堆顶 然后直接remove堆顶元素即可实现出队

十八.哈夫曼树

1.又叫霍夫曼树 最优二叉树
2.哈夫曼编码
在这里插入图片描述

3.如何构建一棵哈夫曼树
在这里插入图片描述
在这里插入图片描述
4.构建哈夫曼编码
在这里插入图片描述

十九.Trie

1.也叫字典树 前缀树 单词查找树
2.搜索效率和字符串的长度有关
3.主要用于查找某棵树中是否包含某单词 或是否以某单词/字母开头
4.根节点为空 啥也不放 根节点到子节点的线上存放字母 节点存放:值 是否为最后一个单词 父节点 子节点
5.trie的每一个节点包括:
parent:父节点 方便删除
boolean word:若为true 则代表该节点是单词的最后一个字母 该单词结尾了
V value:用于存储该节点的值 在test中 cat的值是1 最后一个字母是t 那么t所在节点Word=true value=1
HashMap<Character, Node> children:用于存储子节点 键是字符 值是子节点
character:每个节点对应的字符
6.添加:
思路:在trie中查找是否存在key:
1.存在且t对应的节点的Word为true 表明存在cat单词 用传入的value覆盖原来的value
2.存在且t对应的节点的Word为false 表明存在cat开头的单词 将t对应的节点的Word改为true
3.存在c/ca开头的单词 但不存在cat 添加
4.不存在c开头的单词 依次添加cat
7.删除:
先遍历查找key 若不存在key 则直接返回null
若存在key且key的最后一个字母所在节点有子节点 则将key的最后一个字母所在节点的Word变为false 清空value
若存在key且key的最后一个字母所在节点没有子节点 先将最后一个字母所在节点删除 再判断该节点是否有兄弟节点
若有 则结束 若没有 则判断该节点的父节点是否有兄弟节点 如此循环

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值