当前位置: 首页 > news >正文

AVL、B树和B+树

AVL树定义

AVL树(Adelson-Velsky 和 Landis 树)是一种自平衡的二叉搜索树(Binary Search Tree, BST),由苏联数学家Georgy Adelson-Velsky和Evgenii Landis在1962年提出。AVL树通过在每个节点上维护一个平衡因子(Balance Factor),确保树的高度始终保持在对数级别,从而保证查找、插入和删除操作的时间复杂度为O(log N)。

主要特性
  1. 二叉搜索树性质

    • 每个节点的左子树中所有节点的值均小于该节点的值。
    • 每个节点的右子树中所有节点的值均大于该节点的值。
  2. 高度平衡

    • 对于每个节点,其左子树和右子树的高度差(平衡因子)最多为1,即:
      ∣ 左子树高度 − 右子树高度 ∣ ≤ 1 | \text{左子树高度} - \text{右子树高度} | \leq 1 左子树高度右子树高度1
    • 通过旋转操作在插入或删除节点后保持树的平衡。
  3. 平衡因子

    • 每个节点维护一个平衡因子,定义为其左子树的高度减去右子树的高度:
      平衡因子 = 左子树高度 − 右子树高度 \text{平衡因子} = \text{左子树高度} - \text{右子树高度} 平衡因子=左子树高度右子树高度
    • 平衡因子的取值范围为-1、0、+1。
      在这里插入图片描述
旋转操作

当插入或删除节点导致某个节点的平衡因子超出范围时,需要通过旋转操作来恢复AVL树的平衡。主要的旋转操作包括:

  1. 单右旋(Right Rotation)

    • 用于解决左-左(LL)失衡的情况。
  2. 单左旋(Left Rotation)

    • 用于解决右-右(RR)失衡的情况。
  3. 双旋转(Left-Right Rotation 和 Right-Left Rotation)

    • 用于解决左-右(LR)和右-左(RL)失衡的情况。
优点
  • 高效的查找性能:由于严格的平衡条件,AVL树的查找、插入和删除操作的时间复杂度均为O(log N)。
  • 动态平衡:插入和删除操作后自动调整,保持树的平衡,避免退化为链表结构。
缺点
  • 维护复杂性:插入和删除操作后可能需要进行多次旋转,增加了实现的复杂性。
  • 额外的内存消耗:每个节点需要存储平衡因子或高度信息,增加了内存开销。
应用场景

AVL树适用于需要频繁查找、插入和删除操作的动态数据集,如:

  • 数据库索引:保证高效的数据检索和更新。
  • 内存中的符号表:如编译器中的符号表管理。
  • 实时系统:需要快速响应的应用场景。
示例

以下是一个简单的AVL树节点结构的示例(以C语言为例):

typedef struct AVLNode {int key;struct AVLNode *left;struct AVLNode *right;int height;
} AVLNode;

在这个结构中,每个节点包含一个键值、指向左子节点和右子节点的指针,以及存储该节点高度的字段。

总结

AVL树通过严格的高度平衡条件,确保了二叉搜索树的操作效率,特别适合需要频繁动态更新和高效查找的应用场景。尽管在实现上比普通的二叉搜索树更为复杂,但其在性能上的优势使其在许多系统中得到了广泛应用。

B树

早上好!我很乐意帮你修改文本,让我们添加适当的LaTeX标记。

B树的结构与性质分析

  1. 节点的孩子数
  • 每个节点最多有 m m m 个子节点( m ≥ 2 m \geq 2 m2)。
  • 除根节点和叶子节点外,其他每个非叶子节点必须至少有 ⌈ m / 2 ⌉ \lceil m / 2 \rceil m/2 个孩子。
  • ⌈ m / 2 ⌉ \lceil m / 2 \rceil m/2:表示向上取整的函数,它确保了树的平衡性。例如,对于 m = 5 m = 5 m=5,最少需要 ⌈ 5 / 2 ⌉ = 3 \lceil 5 / 2 \rceil = 3 5/2=3 个子节点。
  1. 根节点的特殊情况
  • 根节点必须至少有2个孩子,除非根节点是叶子节点。在这种情况下,整棵树只有根节点,它既是叶子节点也是根节点。
  1. 叶子节点的特性
  • 所有叶子节点都出现在同一层级:这确保了树的平衡性,所有查找操作的路径长度一致,从而提高查找效率。
  • 叶子节点不包含关键字信息:叶子节点通常不包含实际的关键字数据,可能包含数据的指针或者是表示查询失败的空指针。实际上,这些节点依然存在,只是它们没有指向其他子节点的指针。
  1. 非叶子节点的结构
    每个非叶子节点包含若干个关键字( n n n个)和指向子树的指针( P 0 , P 1 , . . . , P n P_0, P_1, ..., P_n P0,P1,...,Pn)。具体结构如下:
  • 关键字:每个非叶子节点包含有 n n n 个关键字 K 1 , K 2 , . . . , K n K_1, K_2, ..., K_n K1,K2,...,Kn,且这些关键字按升序排列,即 K i − 1 < K i K_{i-1} < K_i Ki1<Ki i = 1 , 2 , . . . , n i = 1, 2, ..., n i=1,2,...,n)。
  • 子树指针:每个非叶子节点有 n + 1 n+1 n+1 个子树指针 P 0 , P 1 , . . . , P n P_0, P_1, ..., P_n P0,P1,...,Pn,每个子树指针 P i P_i Pi 指向一个子树,且子树中的所有关键字都小于 K i K_i Ki 并大于 K i − 1 K_{i-1} Ki1(对于 i = 1 i = 1 i=1,指针 P 0 P_0 P0 指向所有小于 K 1 K_1 K1 的关键字)。
  1. 关键字的个数
  • 对于每个非根节点(即非叶子节点),包含的关键字数 n n n 必须满足以下条件: ⌈ m / 2 ⌉ − 1 ≤ n ≤ m − 1 \lceil m / 2 \rceil - 1 \leq n \leq m - 1 m/21nm1

这意味着每个节点的关键字数至少是 ⌈ m / 2 ⌉ − 1 \lceil m / 2 \rceil - 1 m/21,而最多是 m − 1 m - 1 m1,从而控制了节点的密度,防止树的某部分过于稀疏或过于密集,保证了树的平衡。


图示结构说明

假设我们考虑一个3阶( m = 3 m = 3 m=3)B树的例子。按照您给出的规则,3阶B树的结构会是这样的:

  • 节点最多含有2个子节点
  • 每个非根节点至少含有1个子节点
  • 每个节点最多含有2个关键字
  • 所有叶子节点都在同一层。

例如,一棵3阶B树的具体结构如下:

[30]
/ \
[10,20] [40,50]

其中:

  • 根节点包含一个关键字 30 30 30 和两个子树指针。
  • 每个子树的根节点(如 [ 10 , 20 ] [10,20] [10,20] [ 40 , 50 ] [40,50] [40,50])分别包含两个关键字,并且每个子树都至少有 1 个子节点。
  • 所有叶子节点( [ 10 , 20 ] [10,20] [10,20] [ 40 , 50 ] [40,50] [40,50])都在同一层,且没有子节点,通常这些叶子节点会存储实际的数据(在实际应用中可能是指向数据记录的指针)。

B树(B-Tree)实现示例

下面将以 Python 语言实现一个 B树,遵循您提供的详细定义和属性。此实现包括节点结构、插入和搜索操作。由于删除操作相对复杂,为了保持示例简洁,本文主要集中在插入和搜索功能上。

1. B树的基本结构

首先,定义B树节点的结构。每个节点包含以下部分:

  • keys:存储节点中的关键字,按照升序排列。
  • children:指向子节点的指针列表。
  • leaf:布尔值,指示节点是否为叶子节点。

2. B树类的实现

以下是B树的完整实现,包括插入和搜索功能:

import mathclass BTreeNode:def __init__(self, t, leaf=False):"""初始化B树节点:param t: 最小度数(ceil(m/2)):param leaf: 是否为叶子节点"""self.t = t  # 最小度数self.keys = []  # 存储关键字self.children = []  # 存储子节点self.leaf = leaf  # 是否为叶子节点def __str__(self):return f'Keys: {self.keys}, Leaf: {self.leaf}'class BTree:def __init__(self, m):"""初始化B树:param m: 阶数"""if m < 3:raise ValueError("阶数m必须大于等于3")self.m = m  # 阶数self.t = math.ceil(m / 2)  # 最小度数self.root = BTreeNode(self.t, leaf=True)def search(self, k, x=None):"""在B树中搜索关键字k:param k: 关键字:param x: 当前节点:return: 节点和关键字的位置"""if x is None:x = self.rooti = 0while i < len(x.keys) and k > x.keys[i]:i += 1if i < len(x.keys) and k == x.keys[i]:return (x, i)elif x.leaf:return Noneelse:return self.search(k, x.children[i])def insert(self, k):"""向B树中插入关键字k:param k: 关键字"""root = self.rootif len(root.keys) == self.m - 1:# 根节点已满,需要分裂s = BTreeNode(self.t, leaf=False)s.children.insert(0, self.root)self.split_child(s, 0)self.root = sself.insert_non_full(s, k)else:self.insert_non_full(root, k)def insert_non_full(self, x, k):"""在非满节点x中插入关键字k:param x: 当前节点:param k: 关键字"""i = len(x.keys) - 1if x.leaf:# 插入到叶子节点x.keys.append(None)  # 占位while i >= 0 and k < x.keys[i]:x.keys[i + 1] = x.keys[i]i -= 1x.keys[i + 1] = kelse:# 找到子节点while i >= 0 and k < x.keys[i]:i -= 1i += 1if len(x.children[i].keys) == self.m - 1:# 子节点已满,分裂self.split_child(x, i)if k > x.keys[i]:i += 1self.insert_non_full(x.children[i], k)def split_child(self, x, i):"""分裂子节点x.children[i]:param x: 父节点:param i: 子节点的索引"""t = self.ty = x.children[i]z = BTreeNode(t, leaf=y.leaf)# 分裂y的keys和children到zz.keys = y.keys[t:]y.keys = y.keys[:t - 1]if not y.leaf:z.children = y.children[t:]y.children = y.children[:t]# 插入z到x的childrenx.children.insert(i + 1, z)# 将中间键上移到xx.keys.insert(i, y.keys.pop(-1))def traverse(self, x=None, depth=0):"""遍历B树并打印:param x: 当前节点:param depth: 当前深度"""if x is None:x = self.rootprint("  " * depth + str(x))if not x.leaf:for child in x.children:self.traverse(child, depth + 1)def delete(self, k):"""删除B树中的关键字k:param k: 关键字"""self.delete_internal(self.root, k)# 如果根节点的关键字为空,调整根if len(self.root.keys) == 0 and not self.root.leaf:self.root = self.root.children[0]def delete_internal(self, x, k):"""在节点x中删除关键字k:param x: 当前节点:param k: 关键字"""t = self.ti = 0while i < len(x.keys) and k > x.keys[i]:i += 1if i < len(x.keys) and k == x.keys[i]:if x.leaf:# 情况1: k在叶子节点x中x.keys.pop(i)else:# 情况2: k在非叶子节点x中y = x.children[i]z = x.children[i + 1]if len(y.keys) >= t:pred = self.get_predecessor(y)x.keys[i] = predself.delete_internal(y, pred)elif len(z.keys) >= t:succ = self.get_successor(z)x.keys[i] = succself.delete_internal(z, succ)else:self.merge(x, i)self.delete_internal(y, k)elif not x.leaf:# 情况3: k不在节点x中,且x不是叶子节点flag = (i == len(x.keys))if len(x.children[i].keys) < t:self.fill(x, i)if flag and i > len(x.keys):self.delete_internal(x.children[i - 1], k)else:self.delete_internal(x.children[i], k)def get_predecessor(self, x):"""获取节点x的前驱关键字:param x: 当前节点:return: 前驱关键字"""while not x.leaf:x = x.children[-1]return x.keys[-1]def get_successor(self, x):"""获取节点x的后继关键字:param x: 当前节点:return: 后继关键字"""while not x.leaf:x = x.children[0]return x.keys[0]def fill(self, x, i):"""确保x.children[i]有至少t个关键字:param x: 当前节点:param i: 子节点索引"""t = self.tif i != 0 and len(x.children[i - 1].keys) >= t:self.borrow_from_prev(x, i)elif i != len(x.children) - 1 and len(x.children[i + 1].keys) >= t:self.borrow_from_next(x, i)else:if i != len(x.children) - 1:self.merge(x, i)else:self.merge(x, i - 1)def borrow_from_prev(self, x, i):"""从x.children[i-1]借一个关键字到x.children[i]:param x: 当前节点:param i: 子节点索引"""child = x.children[i]sibling = x.children[i - 1]# 移动x的keychild.keys.insert(0, x.keys[i - 1])if not child.leaf:child.children.insert(0, sibling.children.pop(-1))x.keys[i - 1] = sibling.keys.pop(-1)def borrow_from_next(self, x, i):"""从x.children[i+1]借一个关键字到x.children[i]:param x: 当前节点:param i: 子节点索引"""child = x.children[i]sibling = x.children[i + 1]# 移动x的keychild.keys.append(x.keys[i])if not child.leaf:child.children.append(sibling.children.pop(0))x.keys[i] = sibling.keys.pop(0)def merge(self, x, i):"""合并x.children[i]和x.children[i+1]:param x: 当前节点:param i: 子节点索引"""child = x.children[i]sibling = x.children[i + 1]t = self.t# 移动x的key到childchild.keys.append(x.keys.pop(i))# 合并sibling的keys到childchild.keys.extend(sibling.keys)# 合并sibling的子节点到childif not child.leaf:child.children.extend(sibling.children)# 移除siblingx.children.pop(i + 1)# 示例使用
if __name__ == "__main__":# 创建一个阶数为4的B树(每个节点最多有3个关键字和4个子节点)btree = BTree(m=4)# 插入关键字keys_to_insert = [10, 20, 5, 6, 12, 30, 7, 17]for key in keys_to_insert:btree.insert(key)print(f"插入关键字 {key} 后的B树结构:")btree.traverse()print("-" * 50)# 搜索关键字search_keys = [6, 15]for key in search_keys:result = btree.search(key)if result:node, idx = resultprint(f"找到关键字 {key} 在节点: {node}, 索引位置: {idx}")else:print(f"关键字 {key} 不存在于B树中。")# 删除关键字keys_to_delete = [6, 13, 7, 4, 2, 16]for key in keys_to_delete:print(f"\n删除关键字 {key} 后的B树结构:")btree.delete(key)btree.traverse()print("-" * 50)

3. 代码详解

3.1 BTreeNode 类
class BTreeNode:def __init__(self, t, leaf=False):self.t = t  # 最小度数self.keys = []  # 存储关键字self.children = []  # 存储子节点self.leaf = leaf  # 是否为叶子节点def __str__(self):return f'Keys: {self.keys}, Leaf: {self.leaf}'
  • t(最小度数):根据阶数 ( m ),最小度数 ( t = \lceil m/2 \rceil )。
  • keys:关键字列表,始终保持有序。
  • children:子节点列表。
  • leaf:布尔值,指示节点是否为叶子节点。
3.2 BTree 类
class BTree:def __init__(self, m):if m < 3:raise ValueError("阶数m必须大于等于3")self.m = m  # 阶数self.t = math.ceil(m / 2)  # 最小度数self.root = BTreeNode(self.t, leaf=True)
  • m(阶数):每个节点最多有 ( m-1 ) 个关键字和 ( m ) 个子节点。
  • t(最小度数):每个节点至少有 ( t-1 ) 个关键字(根节点除外)。
  • root(根节点):初始时为叶子节点。
3.3 插入操作

插入操作分为两部分:

  1. insert 方法:处理根节点是否需要分裂的情况。
  2. insert_non_full 方法:在非满节点中插入关键字。
  3. split_child 方法:分裂满节点。
def insert(self, k):root = self.rootif len(root.keys) == self.m - 1:# 根节点已满,需要分裂s = BTreeNode(self.t, leaf=False)s.children.insert(0, self.root)self.split_child(s, 0)self.root = sself.insert_non_full(s, k)else:self.insert_non_full(root, k)
  • 如果根节点已满,则创建一个新的根节点,并分裂原根节点。
def insert_non_full(self, x, k):i = len(x.keys) - 1if x.leaf:# 插入到叶子节点x.keys.append(None)  # 占位while i >= 0 and k < x.keys[i]:x.keys[i + 1] = x.keys[i]i -= 1x.keys[i + 1] = kelse:# 找到子节点while i >= 0 and k < x.keys[i]:i -= 1i += 1if len(x.children[i].keys) == self.m - 1:# 子节点已满,分裂self.split_child(x, i)if k > x.keys[i]:i += 1self.insert_non_full(x.children[i], k)
  • 叶子节点:直接插入关键字,保持有序。
  • 非叶子节点:找到合适的子节点,若子节点已满,则先分裂,再递归插入。
def split_child(self, x, i):t = self.ty = x.children[i]z = BTreeNode(t, leaf=y.leaf)# 分裂y的keys和children到zz.keys = y.keys[t:]y.keys = y.keys[:t - 1]if not y.leaf:z.children = y.children[t:]y.children = y.children[:t]# 插入z到x的childrenx.children.insert(i + 1, z)# 将中间键上移到xx.keys.insert(i, y.keys.pop(-1))
  • 将满的子节点 y 分裂为两个节点 yz,并将中间关键字上移到父节点 x
3.4 搜索操作
def search(self, k, x=None):if x is None:x = self.rooti = 0while i < len(x.keys) and k > x.keys[i]:i += 1if i < len(x.keys) and k == x.keys[i]:return (x, i)elif x.leaf:return Noneelse:return self.search(k, x.children[i])
  • 从根节点开始,递归搜索关键字 k
  • 若找到,返回包含关键字的节点和索引;否则,返回 None
3.5 遍历操作
def traverse(self, x=None, depth=0):if x is None:x = self.rootprint("  " * depth + str(x))if not x.leaf:for child in x.children:self.traverse(child, depth + 1)
  • 以层级形式遍历并打印B树结构,便于可视化。
3.6 删除操作

删除操作较为复杂,涉及多种情况的处理。以下是删除关键字的主要方法:

def delete(self, k):self.delete_internal(self.root, k)# 如果根节点的关键字为空,调整根if len(self.root.keys) == 0 and not self.root.leaf:self.root = self.root.children[0]
  • 调用内部方法 delete_internal 删除关键字。
  • 若删除后根节点无关键字且不是叶子节点,则更新根节点。
def delete_internal(self, x, k):t = self.ti = 0while i < len(x.keys) and k > x.keys[i]:i += 1if i < len(x.keys) and k == x.keys[i]:if x.leaf:# 情况1: k在叶子节点x中x.keys.pop(i)else:# 情况2: k在非叶子节点x中y = x.children[i]z = x.children[i + 1]if len(y.keys) >= t:pred = self.get_predecessor(y)x.keys[i] = predself.delete_internal(y, pred)elif len(z.keys) >= t:succ = self.get_successor(z)x.keys[i] = succself.delete_internal(z, succ)else:self.merge(x, i)self.delete_internal(y, k)elif not x.leaf:# 情况3: k不在节点x中,且x不是叶子节点flag = (i == len(x.keys))if len(x.children[i].keys) < t:self.fill(x, i)if flag and i > len(x.keys):self.delete_internal(x.children[i - 1], k)else:self.delete_internal(x.children[i], k)
  • 情况1:关键字在叶子节点中,直接删除。
  • 情况2:关键字在非叶子节点中,找到前驱或后继关键字替代后递归删除。
  • 情况3:关键字不在当前节点中,递归到合适的子节点删除,确保节点至少有 t 个关键字。

其他辅助方法包括获取前驱、后继、借用关键字以及合并节点等。

4. 示例运行

if __name__ == "__main__":# 创建一个阶数为4的B树(每个节点最多有3个关键字和4个子节点)btree = BTree(m=4)# 插入关键字keys_to_insert = [10, 20, 5, 6, 12, 30, 7, 17]for key in keys_to_insert:btree.insert(key)print(f"插入关键字 {key} 后的B树结构:")btree.traverse()print("-" * 50)# 搜索关键字search_keys = [6, 15]for key in search_keys:result = btree.search(key)if result:node, idx = resultprint(f"找到关键字 {key} 在节点: {node}, 索引位置: {idx}")else:print(f"关键字 {key} 不存在于B树中。")# 删除关键字keys_to_delete = [6, 13, 7, 4, 2, 16]for key in keys_to_delete:print(f"\n删除关键字 {key} 后的B树结构:")btree.delete(key)btree.traverse()print("-" * 50)
4.1 插入操作输出示例
插入关键字 10 后的B树结构:
Keys: [10], Leaf: True
--------------------------------------------------
插入关键字 20 后的B树结构:
Keys: [10, 20], Leaf: True
--------------------------------------------------
插入关键字 5 后的B树结构:
Keys: [5, 10, 20], Leaf: True
--------------------------------------------------
插入关键字 6 后的B树结构:
Keys: [5, 6, 10, 20], Leaf: True
--------------------------------------------------
插入关键字 12 后的B树结构:
Keys: [5, 6, 10, 12, 20], Leaf: True
--------------------------------------------------
插入关键字 30 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5, 6], Leaf: TrueKeys: [10, 12, 20, 30], Leaf: True
--------------------------------------------------
插入关键字 7 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5, 6, 7], Leaf: TrueKeys: [10, 12, 20, 30], Leaf: True
--------------------------------------------------
插入关键字 17 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5, 6, 7], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------
4.2 搜索操作输出示例
找到关键字 6 在节点: Keys: [5, 6, 7], Leaf: True, 索引位置: 1
关键字 15 不存在于B树中。
4.3 删除操作输出示例
删除关键字 6 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5, 7], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------删除关键字 13 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5, 7], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------删除关键字 7 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------删除关键字 4 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------删除关键字 2 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------删除关键字 16 后的B树结构:
Keys: [10, 20], Leaf: FalseKeys: [5], Leaf: TrueKeys: [10, 12, 17, 20, 30], Leaf: True
--------------------------------------------------

5. 代码功能总结

  • 节点分裂:当插入导致节点关键字数量超过最大限制时,节点被分裂,并将中间关键字上移到父节点。
  • 关键字插入:关键字被插入到合适的位置,保持节点内关键字有序。
  • 关键字搜索:通过递归搜索找到目标关键字所在的节点。
  • 关键字删除:处理多种删除情况,确保B树的平衡性,包括关键字的借用和节点的合并。

6. 扩展功能

为了全面实现B树,您可以考虑添加以下功能:

  • 删除操作的完整实现:当前实现已包含基本的删除逻辑,但在某些复杂情况下可能需要更多测试和调整。
  • 可视化工具:使用图形库如 graphviz 进行B树的可视化展示。
  • 批量插入与删除:优化插入和删除操作以支持批量处理,提高效率。

7. 参考资料

  • 《算法导论》(Introduction to Algorithms) - Cormen, Leiserson, Rivest, Stein
  • Wikipedia - B-tree

希望这个B树的Python实现能够帮助您更好地理解和应用B树数据结构。如有任何疑问或需要进一步的功能扩展,请随时提问!

相关文章:

AVL、B树和B+树

AVL树定义 AVL树&#xff08;Adelson-Velsky 和 Landis 树&#xff09;是一种自平衡的二叉搜索树&#xff08;Binary Search Tree, BST&#xff09;&#xff0c;由苏联数学家Georgy Adelson-Velsky和Evgenii Landis在1962年提出。AVL树通过在每个节点上维护一个平衡因子&#…...

[SWPUCTF 2021 新生赛]include

参考博客: 文件包含 [SWPUCTF 2021 新生赛]include-CSDN博客 NSSCTF | [SWPUCTF 2021 新生赛]include-CSDN博客 考点:php伪协议和文件包含 PHP伪协议详解-CSDN博客 php://filter php://filter可以获取指定文件源码。当它与包含函数结合时&#xff0c;php://filter流会被当…...

ES----安装 elasticsearch入门,elasticsearch安装,centos安装es,centos安装elasticsearch

ES 如需要对应资源&#xff0c;请评论留言&#xff0c;或再最后视频中关注获取 1. 安装 1.1 安装es 创建网络&#xff08;centos系统&#xff0c;docker环境&#xff09; docker network create es-netdocker安装es —如果下载失败&#xff0c;请看我的docker配置镜像的文章…...

探索文件系统,Python os库是你的瑞士军刀

文章目录 探索文件系统&#xff0c;Python os库是你的瑞士军刀第一部分&#xff1a;背景介绍第二部分&#xff1a;os库是什么&#xff1f;第三部分&#xff1a;如何安装os库&#xff1f;第四部分&#xff1a;简单库函数使用方法1. 获取当前工作目录2. 改变当前工作目录3. 列出目…...

android studio引用so库

在工程中编译好的so库文件将在原始编译工程对应目录下&#xff1a;build/intermediates/cxx/Debug/xxxxxx/obj/ 其目录结构如上所示&#xff0c;包含生成的四个版本&#xff0c;每个文件夹下均包含c/c源码编译成的Android版本的libnavi.so库和提供应用接口的libnavi-lib.so库。…...

Ubuntu 服务器部署 Tomcat 并配置 SSL/TLS 证书

本文目录 准备登陆云服务器安装 Java下载 tomcat 包配置防火墙浏览器访问 Tomcat 默认页面以服务的形式运行 Tomcat创建 Tomcat 用户和组创建 systemd 服务文件启动 tomcat 服务 Tomcat webapps 文件目录部署一个静态网站tomcat 的配置文件 将域名解析到服务器Tomcat 配置 SSL/…...

不间断电源 (UPS) 对现代技术可靠性的影响

在这个技术型世界里&#xff0c;无论是在个人还是商业环境中&#xff0c;电力供应商提供的稳定供电都变得越来越重要。 不间断电源 (UPS) 系统是一种不可或缺的解决方案&#xff0c;可保证终端设备不受干扰地运行&#xff0c;在出现电源问题或故障时让用户继续工作。 这篇文章…...

Android 基础类(01)- Thread类 - readyToRun和threadLoop

一、前言&#xff1a; 在阅读AOSP代码过程中&#xff0c;我们经常会看到Thread子类重写两个方法&#xff1a;readyToRun和threadLoop&#xff0c;不清楚的同学&#xff0c;可能在这儿连调用逻辑都搞不清楚了&#xff0c;因为找不到谁调用了它。我这儿先不去深究Thread内部逻辑…...

【组件封装】uniapp vue3 封装一个自定义下拉刷新组件pullRefresh,带刷新时间和加载动画教程

文章目录 前言一、实现原理二、组件样式和功能设计三、scroll-view 自定义下拉刷新使用回顾相关属性&#xff1a;最终版完整代码&#xff1a; 前言 手把手教你封装一个移动端 自定义下拉刷新组件带更新时间和加载动画&#xff08;PullRefresh&#xff09;&#xff0c;以uniapp …...

通过 JNI 实现 Java 与 Rust 的 Channel 消息传递

做纯粹的自己。“你要搞清楚自己人生的剧本——不是父母的续集&#xff0c;不是子女的前传&#xff0c;更不是朋友的外篇。对待生命你不妨再大胆一点&#xff0c;因为你好歹要失去它。如果这世上真有奇迹&#xff0c;那只是努力的另一个名字”。 一、crossbeam_channel 参考 cr…...

一起学习Fortran:如何安装Fortran

Fortran&#xff08;全称Formula Translation&#xff0c;意为“公式翻译”&#xff09;是一种通用编译命令式编程语言&#xff0c;适用于数值计算和科学计算。Fortran语言最初是由IBM在20世纪50年代为科学和工程应用程序而开发的&#xff0c;第一个Fortran版本——FORTRAN I在…...

社交新零售模式下“2+1 链动模式 S2B2C 商城小程序”的创新实践与发展策略

摘要&#xff1a;随着实体商业与社交网络深度融合&#xff0c;社交新零售蓬勃兴起&#xff0c;“21 链动模式 S2B2C 商城小程序”作为其中创新典范&#xff0c;融合独特激励机制与数字化运营优势&#xff0c;重塑零售生态。本文剖析该模式架构、运作逻辑&#xff0c;探讨其在私…...

【博主推荐】C# Winform 拼图小游戏源码详解(附源码)

文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代&#xff0c;程序开…...

贝叶斯统计的核心思想与基础知识:中英双语

中文版 贝叶斯统计的核心思想与基础知识 贝叶斯统计是以贝叶斯定理为核心&#xff0c;通过将先验知识和观测数据相结合&#xff0c;更新对参数或模型的认知的一种统计方法。它不仅强调概率的频率解释&#xff08;频率统计学中概率描述事件的长期发生频率&#xff09;&#xf…...

Verilog使用liberty文件中cell单元的demo

Liberty&#xff08;.lib&#xff09;文件是用来描述标准单元库中逻辑单元&#xff08;如门电路、触发器等&#xff09;的时序和功耗特性的&#xff0c;不是用来直接定义Verilog中的元件。在Verilog设计中&#xff0c;我们通常通过实例化模块&#xff08;module&#xff09;来创…...

openssl生成ca证书

常见CA文件夹 1、生成CA钥匙 openssl genrsa -out ./private/cakey.pem 2、生成CA自签名 openssl req -new -x509 -key ./private/cakey.pem -out ./cacert.crt -days 3650 3、生成http服务器私钥 openssl genrsa -out ./data/frontt.project.com.key 2048 4、CA给http服务器…...

OGRE 3D----2. QGRE + QQuickView

将 OGRE(面向对象图形渲染引擎)集成到使用 QQuickView 的 Qt Quick 应用程序中,可以在现代灵活的 UI 框架中提供强大的 3D 渲染功能。本文将指导您如何在 QQuickView 环境中设置 OGRE。 前提条件 在开始之前,请确保您已安装以下内容: Qt(版本 5.15 )OGRE(版本14.2.5)…...

【Java 学习】面向程序的三大特性:封装、继承、多态

引言 1. 封装1.1 什么是封装呢&#xff1f;1.2 访问限定符1.3 使用封装 2. 继承2.1 为什么要有继承&#xff1f;2.2 继承的概念2.3 继承的语法2.4 访问父类成员2.4.1 子类中访问父类成员的变量2.4.2 访问父类的成员方法 2.5 super关键字2.6 子类的构造方法 3. 多态3.1 多态的概…...

Online Judge——【前端项目初始化】Vue-CLI初始化项目、组件库引入

目录 一、创建项目二、前端工程化配置三、引入组件 一、创建项目 输入命令&#xff1a;vue create oj-frontend来到如下界面&#xff1a; 选择Manually select features 选择如下图的组件&#xff1a;注意空格是选择&#xff0c;之后回车即可。 选择3.x版本 继续选择&#xff…...

ASP.NET Web(.Net Framework)POST无法正常接收数据

ASP.NET Web&#xff08;.Net Framework&#xff09;POST无法正常接收数据 介绍站点Post和Get如何打断点测试测试代码如下服务器站点Post方法修改原因总结 总结 介绍 这一篇文章主要是讲一下之前搭建的HTTP站点POST无法正常接收数据&#xff0c;如果还不知道怎么搭建HTTP站点的…...

vue安装cypress及其部分用法

安装Cypress 在vue中安装Cypress 1. 安装 Cypress 首先&#xff0c;确保你已经安装了 Cypress。在你的 Vue 项目根目录下运行以下命令&#xff1a; npm install cypress --save-dev2. 打开 Cypress 安装完 Cypress 后&#xff0c;可以通过以下命令打开 Cypress 测试界面&a…...

Web Worker 入门:让前端应用多线程化

引出&#xff1a; 作为前端切图仔&#xff0c;在之前的工作中一直都是写后台&#xff0c;没机会用到web Worker&#xff0c;传统的性能优化web Worker用到的场景也很少&#xff0c;毕竟大量的数据计算一般直接给后端去做就行&#xff0c;轮不到前端来考虑&#xff08;没遇到类似…...

Vue+Elementui el-tree树只能选择子节点并且支持检索

效果&#xff1a; 只能选择子节点 添加配置添加检索代码 源码&#xff1a; <template><div><el-button size"small" type"primary" clearable :disabled"disabled" click"showSign">危险点评估</el-button>…...

MySQL各种问题的原因及解决方案梳理

背景&#xff1a;由于最近一直在做生产环境和测试环境的切换&#xff0c;遇到了各种各样的MySQL问题&#xff0c;为了后面的开发顺利&#xff0c;梳理一下MySQL的报错及解决方案 问题1、MySQL的链接数超过了本身MySQL内部设置的链接限制 报错信息&#xff1a; // An highlig…...

LeetCode—74. 搜索二维矩阵(中等)

仅供个人学习使用 题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true…...

【Redis】Redis介绍

目录 1.Redis是什么? 2. Redis特性 2.1 速度快 2.2 基于键值对的数据结构服务器 2.3 丰富的功能 2.4 简单稳定 2.5 客户端语言多 2.6 持久化 2.7 主从复制 2.8 高可用和分布式 3. Redis使用场景 3.1 缓存(Cache) 3.2 排行榜系统 3.3 计数器应用 3.4 社交网络 …...

Python 3 教程第23篇(模块)

Python3 模块 在前面的几个章节中我们基本上是用 python 解释器来编程&#xff0c;如果你从 Python 解释器退出再进入&#xff0c;那么你定义的所有的方法和变量就都消失了。 为此 Python 提供了一个办法&#xff0c;把这些定义存放在文件中&#xff0c;为一些脚本或者交互式…...

课题组自主发展了哪些CMAQ模式预报相关的改进技术?

空气污染问题日益受到各级政府以及社会公众的高度重视&#xff0c;从实时的数据监测公布到空气质量数值预报及预报产品的发布&#xff0c;我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…...

七牛云AIGC内容安全方案助力企业合规创新

随着人工智能生成内容(AIGC)技术的飞速发展,内容审核的难度也随之急剧上升。在传统审核场景中,涉及色情、政治、恐怖主义等内容的标准相对清晰明确,但在AIGC的应用场景中,这些界限变得模糊且难以界定。用户可能通过交互性引导AI生成违规内容,为审核工作带来了前所未有的不可预测…...

Vue.js 中的事件处理

在 Vue.js 中&#xff0c;事件处理是用户与应用交互的重要方式。Vue.js 允许开发者以一种声明式的方式来绑定事件监听器&#xff0c;这使得代码更加简洁和易于维护。本文将介绍 Vue.js 中的事件处理&#xff0c;包括常用的事件类型和如何使用它们。 Vue.js 事件基础 在 Vue.j…...

Windows用pm2部署node.js项目

Windows上pm2启动命令不生效 按照常规启动命令应该如下&#xff0c;但是发现不生效 pm2 start npm --name "project-name" -- start具体如下&#xff0c;可以看到状态都是stopped $ pm2 start npm --name "chatgpt-next-web" -- start [PM2] Starting …...

算法【Java】—— 动态规划之路径问题

前言 本文章终点解析第一道题目【不同路径】和最后一道题目【地下城游戏】的动态规划思路&#xff0c;中间几道题目会很快过完&#xff0c;大家如果不熟悉动态规划的思路可以重点看一下这两道题目的解析。 不同路径 https://leetcode.cn/problems/unique-paths 解析&#xf…...

DreamFace4.9.0 |AI照片动画师,让照片说话和跳舞

DreamFace是一款有趣的照片动画应用程序&#xff0c;通过AI技术让您的照片唱歌、跳舞甚至说话。只需上传照片并选择歌曲&#xff0c;即可生成动态效果。此外&#xff0c;它还支持图片增强、降噪和高清处理&#xff0c;创建人工智能驱动的头像。无论是让宠物说话还是让朋友唱情歌…...

vue-baidu-map基本使用

vue-baidu-map 是一个基于 Vue.js 的百度地图组件库&#xff0c;它封装了百度地图的 JavaScript API&#xff0c;使得在 Vue 项目中使用百度地图功能更加便捷。下面是如何在 Vue 项目中安装和使用 vue-baidu-map 的步骤&#xff1a; 安装 首先确保你的项目已经集成了 Vue 和 …...

新电脑验机-允许上网,同时禁止windows系统联网自动激活

效果&#xff1a; 重要提示&#xff1a;我虽然得到上图效果&#xff0c;但也不确定是否有坑&#xff0c;不保证商家是否认可。 笔记本电脑七天无理由退货的前提条件是“windows和office未激活”。如何 oobe\bypassnor 绕过开机联网并创建本地账号的方法我就不写了&#xff0c;搜…...

Android 是否支持AB分区

Android 是否支持AB分区 C:\Users\Administrator>adb shell bengal:/ $ su bengal:/ # getprop |grep treble [ro.treble.enabled]: [true] bengal:/ #返回不为空而且为true&#xff0c;那就是支持pt(project treble)分区 进入fastboot模式 adb reboot bootloader查看当前…...

Qt6.8安卓Android开发环境配置

时隔多年&#xff0c;重拾QtCreator下Android开发。发现Qt6下安卓开发环境配置变简单不少&#xff01;只需三步即可在QtCreator下进行Android开发&#xff1a; 一、使用Qt Mantenance Tool进行Android模块的安装&#xff1a; 如果感觉安装网速较慢&#xff0c;可以查看本人另外…...

JavaSE——类与对象(4)

一、静态变量 1.1为什么要有静态变量 现在有一群小朋友在做游戏&#xff0c;不是有新的小朋友加入&#xff0c;请问如何知道现在共有多少人在完&#xff1f;看这段代码&#xff1a; public class first {public static void main(String[] args) {int count 0;child child1 …...

网络编程中的字节序函数htonl()、htons()、ntohl()和ntohs()

目录 1&#xff0c;网络字节序和主机字节序 2. 函数的具体作用 2.1,htonl&#xff08;Host to Network Long&#xff09; 2.2,htons&#xff08;Host to Network Short) 2.3,ntohl&#xff08;Network to Host Long&#xff09; 2.4,ntohs&#xff08;Network to Host Sho…...

如何在HarmonyOS NEXT中处理页面间的数据传递?

大家好&#xff0c;前两天的Mate70的发布&#xff0c;让人热血沸腾啊&#xff0c;不想错过&#xff0c;自学的小伙伴一起啊&#xff0c;今天分享的学习笔记是关于页面间数据伟递的问题&#xff0c;在HarmonyOS NEXT 5.0 中&#xff0c;页面间的数据传递可以有很多种方式&#x…...

【Code First】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列 &#x1f…...

Day28 贪心算法 part02

122.买卖股票的最佳时机II 本题解法很巧妙,本题大家可以先自己思考一下然后再看题解,会有惊喜! class Solution {public int maxProfit(int[] prices) {//分析每一天的情况。只要保证今天买,明天卖可以不亏钱,那就是最大的利润。把每一天可以赚钱的机会都不放过,先把能挣…...

JVM_栈详解一

1、栈的存储单位 **栈中存储什么&#xff1f;**&#xff0c; 每个线程都有自己的栈&#xff0c;栈中的数据都是以栈帧&#xff08;Stack Frame&#xff09;的格式存在。在这个线程上正在执行的每个方法都各自对应一个栈帧&#xff08;Stack Frame&#xff09;。 栈帧是一个内存…...

深入浅出UART驱动开发与调试:从基础调试到虚拟驱动实现

往期内容 本专栏往期内容&#xff1a;Uart子系统 UART串口硬件介绍深入理解TTY体系&#xff1a;设备节点与驱动程序框架详解Linux串口应用编程&#xff1a;从UART到GPS模块及字符设备驱动 解UART 子系统&#xff1a;Linux Kernel 4.9.88 中的核心结构体与设计详解IMX 平台UART驱…...

集成量子光子学(IQP)

IQP 正在成为量子计算的可行替代方案量子源、波导和调制器等领域的研究使这成为可能与 CMOS 技术的兼容意味着工业可扩展性将更加容易 量子光子学的基本组成部分 IQP 系统的基本组成部分包括&#xff1a; 来源&#xff08;例如腔体中的 QD&#xff09; 波导定向耦合器&#…...

【代码随想录|贪心算法02】

122.买股票的最佳时机 题目链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii 好巧妙的一道题啊&#xff0c;做之前完全不会想到这种解法。 局部最优&#xff1a;收集每天正利润 全局最优&#xff1a;求得最大利润 这道题只让你返回最大的利润和&…...

CentOS7 使用xtrabackup备份及恢复

安装备份工具 1.安装Percona yum存储库 sudo yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm安装过程中需要按y继续安装 2.启用Percona Server 5.7存储库 sudo percona-release setup ps573、安装percona-xtrabackup-24 sudo yum -y instal…...

【网络安全设备系列】12、态势感知

0x00 定义&#xff1a; 态势感知&#xff08;Situation Awareness&#xff0c;SA&#xff09;能够检测出超过20大类的云上安全风险&#xff0c;包括DDoS攻击、暴力破解、Web攻击、后门木马、僵尸主机、异常行为、漏洞攻击、命令与控制等。利用大数据分析技术&#xff0c;态势感…...

VM Virutal Box的Ubuntu虚拟机与windows宿主机之间设置共享文件夹(自动挂载,永久有效)

本文参考如下链接 How to access a shared folder in VirtualBox? - Ask Ubuntu &#xff08;1&#xff09;安装增强功能&#xff08;Guest Additions&#xff09; 首先&#xff0c;在网上下载VBoxGuestAdditions光盘映像文件 下载地址&#xff1a;Index of http://…...

【docker集群应用】Docker--harbor私有仓库部署与管理

文章目录 Harbor特性Harbor构成Harbor部署与管理Harbor 部署实例环境准备1. 部署 Docker-Compose 服务2. 部署 Harbor 服务(1) 下载并解压 Harbor 安装程序(2) 修改 Harbor 配置文件 3. 启动 Harbor4. 查看 Harbor 启动镜像5. 创建一个新项目6. 在其他客户端上传镜像 维护管理 …...