数据结构与算法

一、线性数据结构

1.数组

2.链表

3.栈

(1)简介

  • 栈(Stack)只允许在有序的线性数据集合的一端(栈顶top)进行加入数据(push)和移除数据(pop)。按照后进先出(LIFO,Last In First Out)的原理运作。
  • 栈常用一维数组或链表来实现,用数组实现的栈叫做顺序栈,用链表实现的栈叫做链式栈。
  • 在栈中,push和pop的操作都是发生在栈顶。

假设堆栈中有n个元素。
访问:O(n) //最坏情况
插入删除:O(1) //顶端插入和删除元素

4.队列

(1)简介

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

假设队列中有n个元素。
访问:O(n) //最坏情况
插入删除:O(1) //后端插入,前端删除

(2)队列分类

1)单队列
  • 单队列就是常见的队列,每次添加元素时,都是添加到队尾。
  • 单队列又分为顺序队列(数组实现)链式队列(链表实现)
  • 存在的问题:假溢出、越界
    • 顺序队列存在“假溢出”的问题,也就是明明有位置却不能添加的情况。
      假设下图时一个顺序队列,我们将前两个元素1,2出队,并入队两个元素7,8。当进行入队、出队操作的时候,front和rear都会持续往后移动,当rear移动到最后的时候,我们无法再往队列中添加数据,即使数组中还有空余空间,这种现象就是“假溢出”
    • 除了假溢出问题之外,当添加元素8时,rear指针移动到数组之外(越界)

      为了避免当只有一个元素的时候,队头和队尾重合使处理变得麻烦,所以引入两个指针,front 指针指向对头元素,rear 指针指向队列最后一个元素的下一个位置,这样当 front 等于 rear 时,此队列不是还剩一个元素,而是空队列。——From 《大话数据结构》

2)循环队列
3)双端队列
4)优先队列

(3)队列的常见应用场景

二、图

三、堆

四、树

1.树的特点及常用概念

(1)特点

任何一颗非空树只有一个根节点

一棵树具有以下特点:

  • 一棵树中的任意两个结点有且仅有唯一的一条路径连通。
  • 一棵树如果有n个结点,那么它一定恰好有n-1条边。
  • 一棵树不包含回路。

(2)常用概念

以二叉树为例

  • 节点(结点):树中的每个元素都可以统称为节点。
  • 根节点:顶层节点或者说没有父节点的节点。A节点-根节点
  • 父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点。B节点-D节点和E节点的父节点
  • 子节点:一个节点含有的子树的根节点称为该节点的子节点。D节点、E节点-B节点的子节点
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点。D节点和E节点的父节点都是B节点,故D和E为兄弟节点
  • 叶子节点:没有子节点的节点。D、H、F、I都是叶子节点
  • 节点的高度:该节点到叶子节点最长路径所包含的边数。
  • 节点的深度根节点到该节点的路径所包含的边数,根节点的深度为0。
  • 节点的层数:节点的深度+1。
  • 树的高度:根节点的高度。

2.二叉树的分类

  • 二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。
  • 二叉树的分支通常被称作“左子树”“右子树”。并且,二叉树的分支具有左右次序,不能随意颠倒。
  • 二叉树的第i层至多拥有2^(i-1)个节点,深度为k(深度分别为0,1,2,...,k;层数为k+1)的二叉树至多总共有2^(k+1)-1个节点(满二叉树的情况),至少有2^k个节点(完全二叉树,最后一层只有一个节点,其余层是满的的情况)

(1)满二叉树

一个二叉树,如果每一层的节点数都达到了最大值,则这个二叉树就是满二叉树。
如果一个满二叉树的层数为K,那么它的节点总数为2^k-1。

(2)完全二叉树

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

(完全二叉树的最后一层最多是满的,最少只有一个节点,其余层都是满的)

大家可以想象为一棵树从根节点开始扩展,扩展完左子节点才能扩展右子节点,每扩展完一层,才能继续扩展下一层。

完全二叉树的性质:父节点和子节点的序号有着对应关系

(3)平衡二叉树

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

  • 可以是一颗空树。
  • 如果不是空树,它的左右两个子树的高度差的绝对值不超过1(0或者1),并且左右两个子树都是一颗平衡二叉树。

平衡二叉树的常用实现方法有:红黑树、AVL树、替罪羊树、加权平衡树、伸展树等。

(4)补充

这棵树已经退化为一个链表,我们称之为斜树

二叉树相比于链表,由于父子节点以及兄弟节点之间往往具有某种特殊的关系,使得我们在树中对数据进行搜索和修改时,相对于链表更加快捷便利。但如果二叉树退化为一个链表,那么作为树所具有的优秀品质就难以表现出来,效率也会大打折扣。为了避免这种情况,我们希望每个做“家长”(父节点)的都一碗水端平,分给左儿子和右儿子的尽可能一样多,相差最多不超过一层,即平衡二叉树

3.二叉树的存储

二叉树的存储主要分为链式存储顺序存储两种。

(1)链式存储

和链表类似,二叉树的链式存储依靠指针将各个节点串联起来,不需要连续的存储空间

每个节点包含三个属性:

  • data:数据。data不一定是单一的数据,根据不同情况,可以是多个具有不同类型的数据。
  • left:指向左节点。
  • right:指向右节点。

(2)顺序存储

顺序存储就是利用数组进行存储,数组中的每一个位置仅存储节点的data,不存储left和right,子节点的索引通过数组下标完成。

完全二叉树的顺序存储:

根节点的序号为1,对于每个节点Node,假设它存储在数组中下标为i的位置,那么它的左子节点就存储在2i的位置,右子节点存储在2i+1的位置。

非完全二叉树的顺序存储:

如果我们要存储的二叉树不是完全二叉树,在数组中就会出现空隙,导致内存利用率降低。

4.二叉树的遍历

(1)先序遍历

二叉树的先序遍历,就是先输出根节点,再遍历左子树,最后遍历右子树,遍历左子树和右子树的时候,同样遵循先序遍历的规则,也就是说,我们可以递归实现先序遍历。

public void preOrder(TreeNode root){
	if(root == null){
		return;
	}
	system.out.println(root.data);
	preOrder(root.left);
	preOrder(root.right);
}

(2)中序遍历

二叉树的中序遍历,就是先递归中序遍历左子树,再输出根节点的值,再递归中序遍历右子树。
大家可以想象成一巴掌把树压扁,父节点被拍到了左子节点和右子节点的中间。

public void inOrder(TreeNode root){
	if(root == null){
		return;
	}
	inOrder(root.left);
	system.out.println(root.data);
	inOrder(root.right);
}

(3)后序遍历

二叉树的后序遍历,就是先递归后序遍历左子树,再递归后序遍历右子树,最后输出根节点。

public void postOrder(TreeNode root){
	if(root == null){
		return;
	}
    postOrder(root.left);
	postOrder(root.right);
	system.out.println(root.data);
}

五、红黑树

六、布隆过滤器

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值