数据结构-总结

数据结构

分类划分图

在这里插入图片描述

顺序表ArrayList

  • 底层用数组实现,数组可根据需要进行相应的扩容和缩容
  • 顺序表的度量分两种,size表示有效元素的个数,数组.length表示最大容量
  • 增加元素:最好情况在表尾添加O(1);最坏情况在表头添加,原先元素后移O(n);平均O(n)
  • 删除元素:最好情况在表尾删除O(1);最坏情况在表头删除,后续元素前移O(n);平均O(n)
  • 查改元素:因为数组地址连续,符合等差公式,所以查改该元素位置O(1)解决
  • 注意扩容和缩容的时机:size== length时扩容2倍,size==length/4时缩容2倍,最小不能低于默认容量
  • 适用经常查改元素的场合,不适用经常增删元素的场合

顺序栈ArrayStack

  • 可直接由顺序表实现,只能在一端进行增删查元素,默认栈顶在表尾位置
  • 增删查元素:默认是在顺序表的表尾进行操作,O(1)

顺序双端栈ArrayStackDoubleEnd

  • 改进顺序表实现,只能在两端进行增删查操作,表头和表尾
  • 引入两个指针L和R标记两端的栈顶,L从-1开始,R从数组.length开始
  • 扩容时需更新指针
  • 增删查元素:加入了L、R指针,增删查只需操作两者即可,O(1)

顺序队列ArrayQueue

  • 可直接由顺序表实现,在表头队首删除元素,在表尾队尾增加元素
  • 增加元素:在顺序表表尾增加,O(1)
  • 删除元素:在顺序表表头删除,O(n)
  • 查改元素:访问队首角标0,访问队尾角标size-1,O(1)

顺序循环队列ArrayQueueLoop

  • 改进顺序表实现,引入front头指针和rear尾指针,front从0开始,rear从0开始
  • front位置为队首元素;rear位置表示末尾,不存元素,(rear-1)%length是队尾元素
  • 队列为空时 front== rear;队列为满时 (rear+1)%length==front
  • 注意扩容的问题,两个指针更新位置
  • 增加元素:在rear处增加元素,rear+1,O(1)
  • 删除元素:在front++即可,O(1)
  • 查改元素:直接访问front和rear-1,O(1)

顺序集合ArraySet

  • 可直接由顺序表实现,不存储重复元素而已
  • 综合时间复杂度高,不推荐使用

顺序映射ArrayMap

  • 改进顺序表实现,存储的元素是Key-Value键值对,其中Key不能重复
  • 综合时间复杂度高,不推荐使用

单向链表LinkedList

  • 由链式存储方式构成,每个节点有两个部分:数据域,指针域
  • 数据域:存储元素
  • 指针域:存储下一个节点的地址
  • 注意虚拟头节点和头指针的问题
  • 在没有虚拟头节点的情况下,头指针指向第一个元素节点,头指针为空表示链表为空
  • 在有虚拟头节点的情况下,头指针指向虚拟头节点,头节点.next为空表示链表为空
  • 虚拟头节点的数据域不存元素
  • 增加元素:最好情况在表头O(1);最坏情况在表尾,有尾指针的话O(1),否则要从头到尾找到最后一个节点再增加新元素节点O(n),但是我们一般主要考虑增的过程,而不考虑前提,所以还是O(1)
  • 删除元素:最好情况在表头O(1);最坏情况在表尾,无论有没有尾指针,都要从头到尾找到最后一个元素的前驱O(n),但是我们一般主要考虑删的过程,而不考虑前提,所以还是O(1)
  • 查改元素:没有角标支持,从头开始查,O(n)
  • 适用经常增删元素的场合,不适用经常查改元素的场合

链栈LinkedListStack

  • 由单向链表直接实现,同顺序栈原理,默认栈顶在表头

链队列LinkedQueue

  • 由单向链表直接实现,同顺序队列原理,在有尾指针的情况下,队尾在表尾,队首在表头;否则随意
  • 单向循环链表LinkedListSingleCircular改进单向链表实现,让表尾元素指向第一个元素即可(也可指向虚拟头节点,但不推荐)
  • 链式集合LinkedSet由单向链表直接实现,原理同顺序集合
  • 链式映射LinkedMap改进单向链表实现,原理同顺序映射

二叉树BinaryTree

  • 二叉树节点类似链表节点,有三个部分:数据域,左孩子,右孩子
  • 数据域:存储元素值
  • 左孩子:当前节点左子树的根节点
  • 右孩子:当前节点右子树的根节点
  • 第i层最多 2*(i-1)个元素
  • 共i层的二叉树最多2^i-1个元素
  • 节点和边的关系?边数n=n0(度为0的节点数)+n1+n2

二分搜索树BinarySearchTree

  • 在二分搜索树中,对于任何一个节点而言,其左子树小于当前节点的值;右子树大于当前节点的值
  • 没有考虑等于的情况,所以此树不包含重复元素
  • 并且,元素需要具有可比性(Comparable)
  • 增删改查操作的时间复杂度主要和树的高度有关 h=logn 所O(h)=O(logn)
  • 在元素按有序的情况下进入,会退化成链表,极端不平衡,O(n)
  • 二分搜索树按照中序遍历,可得到元素的递增序列,所以此树是有序的
  • 注意删除节点时,分删除最大,删除最小,删除任意
  • 删除节点时注意该节点是否有左右孩子
  • 有左孩子,无右孩子,将左孩子返回
  • 无左孩子,有右孩子,将右孩子返回
  • 有左孩子,有右孩子,将右子树中的最小值suc返回
  • 将被删除节点的右子树删除suc后返给suc的右子树
  • 将被删除节点的左子树直接返给suc的左子树

二分搜索树实现的集合

  • 改进二分搜索树实现,元素E需要具有可比性(Comparable接口)

二分搜索树实现的映射

  • 改进二分搜索树实现,键K需要具有可比性(Comparable接口)

最大堆

  • 最大堆由数组实现,只不过此种二叉树为完全二叉树,所以可以用数组表示
  • 定义:对于任意一个节点而言,其左右子树都不大于该节点
    这个大于比的是优先级!我们这里默认数字大的优先级大,所以要结合
  • 实际场景定义优先级的问题!
  • 最大堆是指优先级大的在上层;最小堆是指优先级小的在上层;
  • 如何获取i节点的左右孩子?
    左孩子下标:i2+1(i从0开始)
    右孩子下标:i
    2+2
  • 如何获取i节点的父亲节点?
    父亲节点坐标:(i-1)/2
  • 如何元素的上浮和下沉?
    上浮:父节点的优先级小,交换位置
    下沉:和孩子结点中优先级 较大的比较,如果小于孩子结点的优先级,交换位置
  • 什么是heapify?
//heapify 将任意的数组整理为堆
	public MaxHeap(E[] arr){
		data=new MyArrayList(arr);
		for(int i=parent(data.getSize()-1);i>=0;i--){
			shiftDown(i);
		}
	}
  • 如何取出优先级大的元素?
  • 优先级最大的在下标0位置,将最后一个元素移到第一个位置,然后在下沉

最大堆实现的优先队列

  • 由最大堆直接实现
  • 进队元素本质是在数组末尾添加元素,然后按照优先级上浮
  • 出队元素本质是取出数组中第一个元素,将最后一个元素移到第一个位置,然后在下沉

Trie前缀树

  • 是一颗多叉树,为啥多叉?前缀树只能处理字符串类型
  • 每一个节点包含:
  • 当前节点结尾是否组成单词 isWord
  • 该节点的孩子们(字符->节点)的K-V映射
  • 前缀树的时间复杂度和字符串的个数无关,和最长字符串的长度m有关 O(m)

AVL平衡树

  • 本质还是二分搜索树,加入了自平衡机制
  • 什么是节点的高度?
    最大子树高度+1
  • 什么是节点的平衡因子?
    左子树的高度减去右子树高度
    何时进行自平衡?LL,RR,LR,RL?
    当添加一个新元素后,进行自平衡调节
    如何实现左旋转?
    将当前结点右孩子的左子树赋给当前节点的右子树
    将当前结点变为当前结点右孩子的左子树
    在这里插入图片描述
    如何实现右旋转?
    类似左旋转
    时间复杂度O(logn)

红黑树

  • 本质还是二分搜索树,加入了黑平衡机制
  • 是2-3树的一种实现方式
  • 什么是2-3树?
    2-3树是最简单的B-树(或-树)结构,其每个非叶节点都有两个或三个子女,而且所有叶都在统一层上。2-3树不是二叉树,其节点可拥有3个孩子。不过,2-3树与满二叉树相似。高为h的2-3树包含的节点数大于等于高度为h的满二叉树的节点数,即至少有2^h-1个节点。
  • 什么是绝对平衡?
    对于任意一个节点,左右子树高度相同
  • 2-3树添加元素的过程如何?
    在这里插入图片描述
  • 什么是2节点,什么是3节点?
    2-节点,含有一个数据域和两个地址域。
    3-节点,含有两个数据域和三个地址域
  • 如何用二叉节点表示3节点?
    在这里插入图片描述
  • 如何在红黑树中添加元素?
    五种情况:
    1、插入比根结点小的元素
    2、插入比根结点大的元素
    3、已有3结点,插入比根结点大的元素
    4、已有3结点,插入最小元素
    5、已有3结点,插入中等元素
  • 何时左旋转?何时右旋转?何时颜色翻转?
    左旋转:右孩子为红,左孩子不为红
    右旋转:左孩子为红,左孩子的左孩子也为红
    颜色翻转:左子树和右子树都为红色时

哈希表HashTable

  • 重点解决的问题:哈希函数的设计,哈希冲突的解决
  • 哈希函数,可以将元素转换为对应数组的角标,但这种转换不一定是一一对应的。
  • 一般哈希函数,直接将元素转化为整型,注意!不全是!特殊的元素有特殊的处理办法!
  • 哈希表本质上就是红黑树(或链表)的数组而已
  • 什么是哈希冲突?不同的元素进过哈希函数计算出相同的角标,即冲突
  • 哈希表如果不解决哈希冲突,就是完全的数组
  • 哈希表如果解决哈希冲突,将元素放入到合适的红黑树中即可
  • 注意哈希表是否需要扩容?需要!不能极端数组,也不能极端红黑树
  • 所以有上界 N/M>upperTol 和下界 N/M<lowerTol ,可自行定义
  • 超过上界扩容,低于下界缩容,注意!扩容和缩容的长度最好是素数!
  • 时间复杂度O(log(N/MP))或者O(N/M)为什么?
    本质是红黑树数组时时间复杂度就是O(log(N/MP))
    本质是链表数组时时间复杂度就是O(N/M)
  • 上述解决哈希冲突的方式是 链地址法
    还有开放地址发?
    1、线性探测法,遇到哈希冲突 +1
    2、平方探测,遇到哈希冲突+1 +4 +9 +16
    3、二次哈希法 +hash2(key)

猜你喜欢

转载自blog.csdn.net/zhang_ye_ye/article/details/89743634