数据结构:树
树的基本定义:
树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
- 每个节点有零个或多个子节点;
- 没有父节点的节点称为根节点;
- 每一个非根节点有且只有一个父节点;
- 除了根节点外,每个子节点可以分为多个不相交的子树;
树的相关术语:
节点的度:
一个节点含有的子树的个数称为该节点的度;

叶节点:
度为0的节点称为叶节点,也可以叫做终端节点

分支节点:
度不为0的节点称为分支节点,也可以叫做非终端节点,显然除了叶子节点之外的节点都为分支节点。

节点的层次:
节点的层次为从节点到根节点的路径中边的条数,并且认为根节点的层次为0,因为根节点到自身的路径中边的条数为0

树的度:
树中所有节点的度的最大值

树的高度(深度):
结点的深度指从根节点(度为1)自顶向下逐层累加至该结点时的深度。树的深度是树中深度最大的结点的深度。
如下图,该树的深度为5

💡1、二叉树:
二叉树的定义就是每个节点最多有两个子节点

二叉树的设计:

代码:
public class TreeNode<Key,Value> {private TreeNode left; //左子节点private TreeNode right; //右子节点private Key key; //存储键private Value value;//存储值public TreeNode(TreeNode left, TreeNode right, Key key, Value value) {this.left = left;this.right = right;this.key = key;this.value = value;}
}
插入方法put实现思想
1如果当前树中没有任何一个节点,则直接把新节点当做根节点使用
2如果当前树不为空,则从根节点开始
3如果新节点的key小于当前节点的key,则继续找当前节点的左子节点;
4如果新节点的key大于当前节点的key,则继续找当前节点的右子节点;
5如果新节点的key等于当前节点的key,则树中已经存在这样的节点,替换该节点的value即可;
插入方法代码:
//记录根节点private TreeNode root;//记录元素个数private int N;public void put(Key key,Value value){root = put(root, key, value); //如果是第一次插入 直接该节点为根节点}//重载递归插入元素public TreeNode put(TreeNode node,Key key,Value value){if (node==null){//如果传入节点为空 则代表当前树中没有元素node=new TreeNode(null,null,key,value);N++;return node;}else {//如果不为空 则需要判断key大小 决定新插入元素是在左子节点还是右子节点int i = key.compareTo(node.key); //需要实现 Comparable<>泛型接口 x.compareTo(y) 若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。if (i<0){ //i<0 表示新插入key 小于父节点key 那么就需要插入左边node.left = put(node.left, key, value);N++;}if (i>0){ //i>0 表示新插入的key 大于父节点key 那么就需要插入到右边node.right=put(node.right,key,value); //递归调用N++;}if (i==0){//i=0 表示当前key 和传入key 相等 那么直接将value覆盖node.value=value;}}return node;
获取方法get实现思想
从根节点开始:
1如果要查询的key小于当前节点的key,则继续找当前节点的左子节点;
2如果要查询的key大于当前节点的key,则继续找当前节点的右子节点;
3如果要查询的key等于当前节点的key,则树中返回当前节点的value;
代码实现:
//查询元素方法 根据key 返回valuepublic Value get(Key key){if (root==null){return null; //当树中为空时 直接返回空}return get(root,key);}//查找递归public Value get(TreeNode node,Key key){int i = key.compareTo(node.key); //和插入同理 进行比较if (i<0){//i<0 表示需要查找的key 比节点key小 那么就继续寻找该节点的左子节点return get(node.left, key);}if (i>0){//i>0 表示要查找的key 比节点的key大 那么就继续寻找该节点的右子节点return get(node.right,key);}else {//i=0 表示找到对应的ke 直接返回对应的valuereturn node.value;}}
删除方法delete实现思想
- 找到被删除节点;
- 找到被删除节点右子树的最小节点minNode
- 删除右子树的最小节点
- 让被删除节点的左子树称为minNode的左子树,被删除节点右子树同理;
- 让被删除节点的父节点指向最小结点minNode

但删除会碰到许多的情况,如下:
1.当找到最小子节点时,如果它还有右子节点,那么还需要将右子节点赋给最小子节点的父节点。
如下图所示,但删除节点2时,找到最小子节点5,但是5节点还有一个右子节点,那么就需要将右子节点重新赋值给最小子节点的父节点也就是图中的8节点。然后在将5节点替换2节点

这部分对应代码
TreeNode sonNode=node.right; //找到右子树根节点 从右子节点开始遍历TreeNode sonFather=node;while (sonNode.left!=null){ //然后遍历寻找右子节点的左子节点sonFather=sonNode; //记录最小左节点的父节点 为了应对最小子节点还有右子节点用 //TODO: bug记录 --顺序错误 应该在sonNode赋值前先将Father赋值 --否则会导致栈溢出sonNode=sonNode.left; //直到找到最左节点 也就是右子树中最小的那个节点}TreeNode minNode=sonNode;//如果最小节点此有右子节点 那么需要将最小节点的右子节点 重新赋值给最小节点的父节点if (minNode.right!=null){sonFather.left=minNode.right; //将最小子节点的父节点 指向该节点的右子节点minNode.right=null; //将minNode 的子节点断开 ---------------> TODO:bug记录点1 此处导致 栈溢出}
删除方法完整代码:
后续可以进一步优化,提取重复代码
//删除元素方法 根据key删除 返回被删除元素valuepublic Value delete(Key key){if (root==null){return null;}return delete(root,key,root);}//递归查找删除方法public Value delete(TreeNode node,Key key,TreeNode father){//同样先要进行查找int i = key.compareTo(node.key);if (i<0){//key比节点key小 继续找左子节点father=node; //父节点变化 -----》TODO bug记录 父节点忘记变化 导致一直是指向根节点return delete(node.left,key,node);//将父节点也传入}else if (i>0){//key 比当前节点key大 继续找右子节点father=node; //父节点变化return delete(node.right,key,node);//将父节点也传入}else { //此时找到了需要删除的key//临时记录 被删除元素的 左节点和右节点 --》需要判空处理 对左右节点//如果发现该节点的左右子节点都为空 那么就直接进行删除即可if (node.left==null&&node.right==null){//如果是根节点 并且树中只有根节点的时候if (N==1){root=null;}if (node.equals(father.left)){father.left=null; //如果该节点是父节点的左子节点 则直接删除}else {father.right=null; //如果是右子节点则直接 则值节删除}N--;return node.value; //返回删除的元素}//到这一步 必定是右子节点为null 左子节点不为null的情况if (node.right==null){ //如果被删除元素右子节点为空 那么直接将被删除元素的左子节点替换即可if (node.equals(father.left)){father.left=node.left;}else {father.right=node.left;}N--;return node.value; //返回删除的元素} else { //到这一步就 是左右子节点都不为null的情况 然后从被删除元素的右子树开始遍历 直到找右子树中最小的元素TreeNode sonNode=node.right; //找到右子树根节点 从右子节点开始遍历TreeNode sonFather=node;while (sonNode.left!=null){ //然后遍历寻找右子节点的左子节点sonFather=sonNode; //记录最小左节点的父节点 为了应对最小子节点还有右子节点用 //TODO: bug记录 --顺序错误 应该在sonNode赋值前先将Father赋值 --否则会导致栈溢出sonNode=sonNode.left; //直到找到最左节点 也就是右子树中最小的那个节点}TreeNode minNode=sonNode;//如果最小节点此有右子节点 那么需要将最小节点的右子节点 重新赋值给最小节点的父节点if (minNode.right!=null){sonFather.left=minNode.right; //将最小子节点的父节点 指向该节点的右子节点minNode.right=null; //将minNode 的子节点断开 ---------------> TODO:bug记录点1 此处导致 栈溢出}//到此所有情况已经判断完毕 可以执行节点删除if (node.equals(father.left)){father.left=minNode;minNode.left=node.left;minNode.right=node.right; //进行删除操作}else {father.right=minNode;minNode.left=node.left;minNode.right=node.right; // 进行删除操作}N--;return node.value; //返回被删除元素}}}
寻找最小值getMin实现思想
搞懂删除方法后,最小值思路就相比很简单了,一直循环或递归左子节点,直到为null即可。
//寻找最小值public Value getMin(){if (root==null){return null;}TreeNode min=root;while (min.left!=null){min=min.left;}return min.value;}
寻找最大值getMax实现思想
与最小值方法同理,无非是从遍历左节点改为了右节点
//寻找最大值public Value getMax(){if (root==null){return null;}TreeNode max=root;while (max.right!=null){max=max.right;}return max.value;}
二叉树遍历:
二叉树的遍历是树中很重要的一个部分了,由于树的结构特殊性,它没有办法从头开始依次向后遍历,所以存在如何遍历,也就是按照什么样的搜索路径进行遍历的问题。

1.前序遍历:
先访问根节点,然后再访问左子树,最后访问右子树
2.中序遍历:
先访问左子树,中间访问根节点,最后访问右子树
3.后序遍历:
先访问左子树,再访问右子树,最后访问根节点

1.前序遍历:
实现思路:
- 把当前结点key放入到队列中;
- 找到当前结点的左子树,如果不为空,则递归遍历左子树;
- 找到当前节点的右子树,如果不为空,则递归遍历右子树;

以该树为例,那么前序遍历的结果应该是:
10-2-1-8-5-3-4-6-9-12-11-16
中序遍历结果应该是:
2-1-8-5-3-4-6-9-10-12-11-16
后序遍历结果应该是:
2-1-8-5-3-4-6-9-12-11-16-10
实现代码:
//前序遍历 从根节点开始——》左子树——》右子树public Queue<Key> preErgodic(){Queue<Key> keys=new Queue<>();preErgodic(root,keys);return keys;}//递归遍历 将遍历到的都添加在队列中private void preErgodic(TreeNode x,Queue<Key> key){if (x==null){return;}key.inQueue(x.key);if (x.left!=null){//如果左子节点不为空 则递归遍历左子节点preErgodic(x.left,key);}if (x.right!=null){preErgodic(x.right,key);}}
运行结果
public static void main(String[] args) {BinaryTree<Integer,String> tree=new BinaryTree<>();tree.put(10,"张三");tree.put(2,"老二");tree.put(1,"老一");tree.put(8,"老八");tree.put(5,"老五");tree.put(9,"老九");tree.put(3,"老三");tree.put(6,"老六");tree.put(4,"老四");tree.put(12,"老十二");tree.put(11,"老十一");tree.put(16,"老十六");Queue<Integer> queue=tree.preErgodic();for (Integer integer : queue) {System.out.println(integer);}System.out.println("------------------中序遍历-------------------------");Queue<Integer> queueMid = tree.midErgodic();for (Integer integer : queueMid) {System.out.println(integer);}System.out.println("---------后序遍历-------------------------");Queue<Integer> queueAfter = tree.afterErgodic();for (Integer integer : queueAfter) {System.out.println(integer);}}
//运行结果
10
2
1
8
5
3
4
6
9
12
11
16------------------------------中序遍历-------------------------
2
1
8
5
3
4
6
9
10
12
11
16
------------------------------后序遍历-------------------------
2
1
8
5
3
4
6
9
12
11
16
10
2.中序遍历:
- 找到当前结点的左子树,如果不为空,则递归遍历左子树;
- 把当前结点key放入到队列中;
- 找到当前节点的右子树,如果不为空,则递归遍历右子树;
代码:
//中序遍历 从左子树开始——》根节点——》右子树public Queue<Key> midErgodic(){Queue<Key> keys=new Queue<>();preErgodic(root,keys);return keys;}//递归遍历 将遍历到的都添加在队列中private void midErgodic(TreeNode x,Queue<Key> key){if (x==null){return;}//先找到左子节点if (x.left!=null){//如果左子节点不为空 则递归遍历左子节点preErgodic(x.left,key);}key.inQueue(x.key);if (x.right!=null){preErgodic(x.right,key);}}
3.后序遍历:
- 找到当前结点的左子树,如果不为空,则递归遍历左子树;
- 找到当前节点的右子树,如果不为空,则递归遍历右子树;
- 把当前结点key放入到队列中;
//后序遍历 从左子树开始——》右子树——》根节点public Queue<Key> afterErgodic(){Queue<Key> keys=new Queue<>();preErgodic(root,keys);return keys;}//递归遍历 将遍历到的都添加在队列中private void afterErgodic(TreeNode x,Queue<Key> key){if (x==null){return;}//先找到左子节点if (x.left!=null){//如果左子节点不为空 则递归遍历左子节点preErgodic(x.left,key);}if (x.right!=null){preErgodic(x.right,key);}key.inQueue(x.key);}
4.层序遍历:
层序遍历,就是从根节点(第一层)开始,依次向下,获取每一层所有结点的值。

以该树为例,那么层序遍历结果是:
10-2-12-1-8-11-16-5-9-3-6-4
实现思路:
- 创建一个队列,存储每一层的节点;
- 使用循环队列中弹出一个节点;
- 然后获取到到当前节点key
- 如果当前节点的左子节点不为空,则把左子结点放入队列中
- 如果当前节点的右子节点不为空,则把右子结点放入队列中

代码:
public Queue<Key> layerErgodic(){Queue<Key> keys=new Queue<>(); //存储遍历结果队列Queue<TreeNode> nodes=new Queue<>();//循环节点队列nodes.inQueue(root); //将根节点添加至循环队列中while (!nodes.isEmpty()){ //如果不为空 则代表还需要判断是否有 子节点判断TreeNode treeNode = nodes.outQueue();keys.inQueue(treeNode.key); //先将该节点加入 结果队列中if (treeNode.left!=null){nodes.inQueue(treeNode.left);}if (treeNode.right!=null){nodes.inQueue(treeNode.right);}}return keys;}//运行结果:
10-2-12-1-8-11-16-5-9-3-6-4-
实际例题:
在力扣的题中,有时候是要求你将每一层作为一个结果输出,比单纯输出顺序要更为复杂一点点。

思路:通过递归的方式+两个队列来实现.
首先将根节点传入父层节点队列,然后检查根节点的左右子节点,将左右子结点添加到子层待搜索队列,父层节点中的所有队列元素取出后,将待搜索的子结点队列作为父节点队列进行递归。然后将每一层的父节点队列作为结果添加即可。
第一层递归。

第二层递归

完整代码:
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/
class Solution {List<List<Integer>> result=new ArrayList<>();public List<List<Integer>> levelOrder(TreeNode root) {//层序遍历 就是广度优先搜索//创建待搜索队列if(root==null){return result;}Queue<TreeNode> queue=new LinkedList<>();queue.offer(root);cenxu(queue);return result;}public void cenxu(Queue queue){ //将根节点和队列传入//将当前节点传入queueList<Integer> r=new ArrayList<>(); //层序结果Queue<TreeNode> waitSearch=new LinkedList<>();//通过两个队列来实现 父队列存放当前层的所有节点 子队列存当前节点的所有子结点while(!queue.isEmpty()){//遍历父节点//先取出所有节点 然后表示是一个层的//存放到结果中TreeNode node=(TreeNode)queue.poll();r.add(node.val);if(node.left!=null){//将当前层级的所有子结点存入 子队列中waitSearch.offer(node.left);}if(node.right!=null){waitSearch.offer(node.right);}}//递归 队列就是下一个的父队列result.add(r);if(waitSearch.isEmpty()){return;}cenxu(waitSearch);}
}
相关文章:
数据结构:树
树的基本定义: 树是一种数据结构,它是由n(n>1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: …...
docker 怎么启动nginx
在Docker中启动Nginx容器是一个简单的过程。以下是启动Nginx容器的步骤: 拉取Nginx镜像: 首先,你需要从Docker Hub拉取Nginx的官方镜像。使用以下命令: docker pull nginx运行Nginx容器: 使用docker run命令来启动一个…...
【智商检测——DP】
题目 代码 #include <bits/stdc.h> using namespace std; const int N 1e510, M 110; int f[N][M]; int main() {int n, k;cin >> n >> k;for(int i 1; i < n; i){int x;cin >> x;f[i][0] __gcd(f[i-1][0], x);for(int j 1; j < min(i, k)…...
YOLOv11改进,YOLOv11添加SAConv可切换空洞卷积,二次创新C3k2结构
摘要 作者提出的技术结合了递归特征金字塔和可切换空洞卷积,通过强化多尺度特征学习和自适应的空洞卷积,显著提升了目标检测的效果。 理论介绍 空洞卷积(Atrous Convolution)是一种可以在卷积操作中插入“空洞”来扩大感受野的技术,更有效地捕捉到图像中的大范围上下文…...
使用R语言优雅的获取任意区域的POI,道路,河流等数据
POI是“Polnt of Information”的缩写,中文可以翻译为“信息点”。是地图上任何非地理意义的有意义的点,如商店,酒吧,加油站,医院,车站等。POI,道路网,河流等是我们日常研究中经常需…...
【设计模式】工厂方法模式 在java中的应用
文章目录 1. 引言工厂方法模式的定义 2. 工厂方法模式的核心概念工厂方法模式的目的和原理与其他创建型模式的比较(如简单工厂和抽象工厂) 3. Java中工厂方法模式的实现基本的工厂方法模式结构示例代码:创建不同类型的日志记录器 4. 工厂方法…...
Pytest框架学习20--conftest.py
conftest.py作用 正常情况下,如果多个py文件之间需要共享数据,如一个变量,或者调用一个方法 需要先在一个新文件中编写函数等,然后在使用的文件中导入,然后使用 pytest中定义个conftest.py来实现数据,参…...
【面试开放题】挫折、问题、擅长、应用技能
1. 项目中遇到的最大挫折是什么?你是如何应对的? 解答思路: 这个问题通常考察你的问题解决能力、抗压能力和团队协作精神。回答时,可以从以下几个角度展开: 问题背景: 描述项目中遇到的具体挑战。是技术难…...
CTF-PWN: 全保护下格式化字符串利用 [第一届“吾杯”网络安全技能大赛 如果能重来] 赛后学习(没思路了)
通过网盘分享的文件:如果能重来.zip 链接: https://pan.baidu.com/s/1XKIJx32nWVcSpKiWFQGpYA?pwd1111 提取码: 1111 --来自百度网盘超级会员v2的分享漏洞分析 格式化字符串漏洞,在printf(format); __int64 sub_13D7() {char format[56]; // [rsp10h] [rbp-40h]…...
C++学习日记---第16天
笔记复习 1.C对象模型 在C中,类内的成员变量和成员函数分开存储 我们知道,C中的成员变量和成员函数均可分为两种,一种是普通的,一种是静态的,对于静态成员变量和静态成员函数,我们知道他们不属于类的对象…...
SOA、分布式、微服务之间的关系和区别?
在当今的软件开发领域,SOA(面向服务架构)、分布式系统和微服务是三个重要的概念。它们各自有着独特的特性和应用场景,同时也存在着密切的关系。以下是关于这三者之间关系和区别的详细分析: 关系 分布式架构的范畴&…...
java基础概念46-数据结构1
一、引入 List集合的三种实现类使用了不同的数据结构! 二、数据结构的定义 三、常见的数据结构 3-1、栈 特点:先进后出,后进先出。 java内存容器: 3-2、队列 特点:先进先出、后进后出。 栈VS队列-小结 3-3、数组 3-…...
Node.js-Mongodb数据库
MongoDB MongoDB是什么? MongoDB是一个基于分布式文件存储的数据库 数据库是什么? 数据库(DataBase)是按照数据结构来组织、存储和管理数据的应用程序(软件) 数据库作用? 对数据进行增、删…...
STM32 ADC --- 知识点总结
STM32 ADC — 知识点总结 文章目录 STM32 ADC --- 知识点总结cubeMX中配置注解单次转换模式、连续转换模式、扫描模式单通道采样的情况单次转换模式:连续转换模式: 多通道采样的情况禁止扫描模式(单次转换模式或连续转换模式)单次…...
技术创新与人才培养并重 软通动力子公司鸿湖万联亮相OpenHarmony人才生态大会
11月27日,由开放原子开源基金会指导,OpenHarmony项目群工作委员会主办的OpenHarmony人才生态大会2024在武汉隆重举办。软通动力子公司鸿湖万联作为OpenHarmony项目群A类捐赠人应邀出席。大会期间,鸿湖万联不仅深度参与了OpenHarmony人才生态年…...
兔子繁衍问题
7-2 兔子繁衍问题 分数 15 全屏浏览 切换布局 作者 徐镜春 单位 浙江大学 一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔…...
汉代风云人物 1晁错
晁错曾是汉景帝的老师。汉景帝登基后,晁错提出削藩建议,这一举措遭到诸多藩国诸侯的强烈反对,由此引发了紧张局势。 袁盎此前曾担任吴国的宰相,晁错觉得袁盎与吴国等藩国关系密切,很可能知晓藩王们谋反的相关情况却没…...
学习threejs,使用specularMap设置高光贴图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.MeshPhongMaterial高…...
【UE5 C++】判断两点连线是否穿过球体
目录 前言 方法一 原理 代码 测试 结果 方法二 原理 一、检查连线与球体的相交情况 二、检查距离与球体半径的关系 三、检查连线与球体的相交 代码 前言 通过数学原理判断空间中任意两点的连线是否穿过球体,再通过射线检测检验算法的正确性。 方法一 …...
【Blender】如何创建空心管道
步骤 1:创建一个圆柱体 添加圆柱体: 在 Object Mode 下按 Shift A > Mesh > Cylinder。 步骤 2:制作空心效果 进入编辑模式: 选中圆柱体,按 Tab 进入 Edit Mode。 删除顶部和底部面: 按 3 进入面选…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...
