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

常用查找算法整理(顺序查找、二分查找、哈希查找、二叉排序树查找、平衡二叉树查找、红黑树查找、B树和B+树查找、分块查找)

常用的查找算法:

  1. 顺序查找:最简单的查找算法,适用于无序或数据量小的情况,逐个元素比较查找目标值。
  2. 二分查找:要求数据有序,通过不断比较中间元素与目标值,将查找范围缩小一半,效率较高。
  3. 哈希查找:利用哈希函数将键值映射到特定存储位置,能在较短时间内实现查找,常用于数据量较大且对查找速度要求高的场景。
  4. 二叉排序树查找:基于二叉排序树数据结构,左子树节点值小于根节点值,右子树节点值大于根节点值,通过比较和递归进行查找。
  5. 平衡二叉树查找:如AVL树、红黑树等,在二叉排序树基础上保持平衡,提高查找效率,适用于数据动态变化频繁的场景。
  6. 红黑树查找:红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是红色或黑色。经常用于编程语言的标准库、操作系统的内存管理、数据库索引。
  7. B树和B+树查找:常用于文件系统和数据库系统的索引结构,能高效处理大量数据的查找和范围查询。
  8. 分块查找:将数据分块,块内无序但块间有序,先确定块再在块内查找,性能介于顺序查找和二分查找之间。
  9. 斐波那契查找和插值查找在特定场景下有其独特的优势,但整体而言,它们不如顺序查找、二分查找等方法常用,

顺序查找

基本概念
顺序查找,也称为线性查找,是在一个数据集合中从第一个元素开始,逐个比较元素,直到找到目标元素或遍历完整个集合为止的查找方法。它适用于无序的线性表,也可用于有序的线性表。

算法实现

  • 一般实现步骤
    • 从数据集合的第一个元素开始。
    • 将当前元素与要查找的目标元素进行比较。
    • 如果当前元素等于目标元素,则查找成功,返回当前元素的位置。
    • 如果当前元素不等于目标元素,则继续比较下一个元素。
    • 重复上述步骤,直到找到目标元素或者遍历完整个数据集合。如果遍历完整个集合仍未找到目标元素,则查找失败,返回特定的标识(如-1)。
  • Python代码示例
def sequential_search(lst, target):for i, element in enumerate(lst):if element == target:return ireturn -1# 测试
lst = [10, 20, 30, 40, 50]
target = 30
print(sequential_search(lst, target))  

时间复杂度

  • 最好情况:目标元素在数据集合的第一个位置,只需比较1次,时间复杂度为 O ( 1 ) O(1) O(1)
  • 最坏情况:目标元素在数据集合的最后一个位置,或者数据集合中根本不存在目标元素,需要比较 n n n次,时间复杂度为 O ( n ) O(n) O(n),其中 n n n是数据集合中元素的个数。
  • 平均情况:假设目标元素在数据集合中的任何位置出现的概率相等,平均需要比较 n + 1 2 \frac{n + 1}{2} 2n+1次,时间复杂度也为 O ( n ) O(n) O(n)

优缺点

  • 优点
    • 算法简单,易于理解和实现。
    • 对数据集合的存储结构没有特殊要求,无论是顺序存储还是链式存储都可以使用。
    • 对于规模较小的数据集合,顺序查找的效率不会有明显的问题,并且在某些特定情况下(如数据集合动态变化频繁,无法进行其他更高效的预处理时),顺序查找是一种可行的选择。
  • 缺点
    • 对于规模较大的数据集合,查找效率较低,因为平均需要比较大量的元素。

适用场景

  • 数据量较小:当数据集合中的元素数量较少时,顺序查找的简单性和直接性使其成为一种合适的选择,因为在这种情况下,查找操作的成本相对较低,不会对性能产生太大影响。
  • 数据无序且动态变化:如果数据是无序的,并且经常需要进行插入和删除操作,导致数据难以进行有效的组织和索引,那么顺序查找可以在不进行额外维护操作的情况下进行查找。
  • 一次性查找:对于只进行偶尔的、一次性的查找操作,而不考虑对整体查找性能进行优化的情况,顺序查找可以快速实现查找功能,而无需为了提高查找效率而引入复杂的算法和数据结构。

二分查找

基本原理
二分查找也称为折半查找,其基本思想是:每次将待查找区间缩小为原来的一半,通过不断比较中间元素与目标元素的大小关系,来确定下一步的查找区间,直到找到目标元素或者确定目标元素不存在为止。

算法实现

  • 一般实现步骤
    • 首先,确定待查找区间的左右边界,左边界left初始化为0,右边界right初始化为数组长度减1。
    • 进入循环,只要left <= right,就继续查找。
    • 在循环中,计算中间位置mid,通常使用mid = left + (right - left) // 2的方式计算,以避免整数溢出。
    • 将中间位置的元素与目标元素进行比较。
      • 如果中间元素等于目标元素,则查找成功,返回中间位置mid
      • 如果中间元素大于目标元素,说明目标元素在中间元素的左侧,更新右边界right = mid - 1
      • 如果中间元素小于目标元素,说明目标元素在中间元素的右侧,更新左边界left = mid + 1
    • 如果循环结束后仍未找到目标元素,则查找失败,返回特定的标识(如-1)。

Python代码示例

def binary_search(lst, target):left, right = 0, len(lst) - 1while left <= right:mid = left + (right - left) // 2if lst[mid] == target:return midelif lst[mid] > target:right = mid - 1else:left = mid + 1return -1# 测试
lst = [10, 20, 30, 40, 50]
target = 30
print(binary_search(lst, target))  

时间复杂度

  • 最好情况:目标元素正好是中间元素,只需比较1次,时间复杂度为 O ( 1 ) O(1) O(1)
  • 最坏情况:需要不断地将区间缩小一半,直到只剩下一个元素,时间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n),其中 n n n是数组中元素的个数。
  • 平均情况:平均时间复杂度也为 O ( l o g 2 n ) O(log_2n) O(log2n)

优缺点

  • 优点
    • 查找速度快,相比于顺序查找,在大规模的有序数据中,二分查找的效率要高得多。
    • 时间复杂度低,对数级别的时间复杂度使得随着数据规模的增大,查找时间的增长相对缓慢。
  • 缺点
    • 要求数据必须是有序的,因此在数据插入或删除操作频繁的情况下,维护数据的有序性可能会带来额外的开销。
    • 对数据的存储结构有一定要求,通常需要使用数组这种支持随机访问的数据结构,对于链表等不支持随机访问的数据结构,二分查找的效率会大大降低。

适用场景

  • 数据量较大且有序:当处理大规模的有序数据集合时,二分查找能够充分发挥其高效的优势,快速定位目标元素。
  • 静态数据:对于相对稳定、不经常进行插入和删除操作的数据,二分查找是一种理想的查找算法,因为不需要频繁地调整数据的顺序来维护有序性。
  • 需要频繁查找:在需要多次进行查找操作的场景下,二分查找的高效性能够显著提高整体的性能,减少查找的总时间。

哈希查找

基本原理

  • 哈希函数:哈希查找的核心是哈希函数,它是一个将数据元素的键值key映射为一个固定大小的整数(通常称为哈希值或哈希码)的函数,用hash(key)表示。理想情况下,哈希函数应该具有良好的均匀性,即对于不同的键值,能够均匀地分布在哈希表的各个位置上,以减少冲突的发生。
  • 哈希表:哈希表是用于存储数据元素的数据结构,它的大小通常是固定的。通过哈希函数计算出的哈希值作为索引,将数据元素存储在哈希表的相应位置上。当需要查找某个数据元素时,再次使用哈希函数计算其键值的哈希值,然后直接访问哈希表中对应的位置,就可以快速找到该元素。

解决冲突的方法

  • 开放定址法:当有新的数据要插入到哈希表中,发现目标位置已经被占用时,就按照一定的规则寻找下一个空闲的位置来插入。常见的探测序列有线性探测、二次探测等。线性探测就是依次探测下一个位置,即(hash(key)+i) % m,其中i = 1,2,3,...m为哈希表的大小。二次探测则是按照(hash(key)+i^2) % m的方式探测。
  • 链地址法:将所有哈希值相同的数据元素存储在一个链表中。当插入一个新元素时,计算其哈希值,然后将其插入到对应的链表头部或尾部。查找时,先计算哈希值找到对应的链表,然后在链表中顺序查找目标元素。

算法实现
以下是使用链地址法实现哈希查找的Python代码示例:

class HashTable:def __init__(self, size):self.size = sizeself.table = [[] for _ in range(size)]def hash_function(self, key):return key % self.sizedef insert(self, key, value):hash_value = self.hash_function(key)self.table[hash_value].append((key, value))def search(self, key):hash_value = self.hash_function(key)for k, v in self.table[hash_value]:if k == key:return vreturn None# 测试
hash_table = HashTable(10)
hash_table.insert(1, 'apple')
hash_table.insert(11, 'banana')
print(hash_table.search(11))  

时间复杂度

  • 理想情况:如果哈希函数设计得非常好,所有的数据元素都均匀地分布在哈希表中,那么每次查找只需要访问一次哈希表,时间复杂度为 O ( 1 ) O(1) O(1)
  • 最坏情况:当所有的数据元素都映射到同一个哈希值时,哈希表退化为一个链表,此时查找的时间复杂度为 O ( n ) O(n) O(n),其中n是数据元素的个数。
  • 平均情况:在合理的哈希函数和适当的负载因子(即哈希表中已存储元素的数量与哈希表大小的比值)下,哈希查找的平均时间复杂度为 O ( 1 ) O(1) O(1)或接近 O ( 1 ) O(1) O(1)

优缺点

  • 优点
    • 查找速度快:在理想情况下,哈希查找能够在常数时间内完成查找操作,这使得它在大规模数据处理中具有很高的效率。
    • 对数据无顺序要求:与二分查找等算法不同,哈希查找不需要数据是有序的,数据可以以任意顺序插入到哈希表中。
  • 缺点
    • 哈希函数设计困难:要设计一个完美的哈希函数是非常困难的,需要考虑数据的分布特点等因素,以避免冲突过多导致性能下降。
    • 空间开销较大:为了减少冲突,通常需要分配比实际数据量更大的哈希表空间,这可能会造成一定的空间浪费。

适用场景

  • 数据快速查找和插入:在需要频繁进行查找和插入操作的场景中,如数据库索引、缓存系统等,哈希查找能够提供高效的性能。
  • 数据唯一性判断:可以利用哈希查找来快速判断数据是否已经存在,例如在查重系统中,通过计算数据的哈希值并在哈希表中查找,可以快速确定数据是否重复。
  • 海量数据处理:在处理海量数据时,哈希查找可以将数据分散到不同的位置,便于进行分布式存储和处理。

树查找

二叉排序树

定义
二叉排序树(Binary Search Tree,BST),也称为二叉查找树、二叉搜索树,它是一种特殊的二叉树。对于树中的任意一个节点,都满足以下性质:

  • 若该节点的左子树不为空,则左子树上所有节点的值均小于该节点的值。
  • 若该节点的右子树不为空,则右子树上所有节点的值均大于该节点的值。
  • 该节点的左子树和右子树也分别是二叉排序树。

示例
以下是一个简单的二叉排序树示例,树中节点的值分别为 50、30、70、20、40、60、80:

        50/  \30    70/  \   / \20   40 60  80

在这个二叉排序树中,节点 50 的左子树(30、20、40)中的所有节点值都小于 50,右子树(70、60、80)中的所有节点值都大于 50。并且节点 30 的左子树(20)节点值小于 30,右子树(40)节点值大于 30,以此类推。

插入操作
插入新节点时,从根节点开始比较。如果新节点的值小于当前节点的值,则在左子树中继续查找插入位置;如果新节点的值大于当前节点的值,则在右子树中继续查找插入位置,直到找到一个空位置插入新节点。

例如,要在上述二叉排序树中插入节点 35,从根节点 50 开始,35 小于 50,进入左子树;35 大于 30,进入 30 的右子树;此时 30 的右子树节点 40 存在,35 小于 40,进入 40 的左子树,发现为空,将 35 插入该位置。

删除操作
删除操作相对复杂,需要分三种情况:

  • 要删除的节点是叶子节点:直接删除该节点即可。
  • 要删除的节点只有一个子节点:用该子节点替换要删除的节点。
  • 要删除的节点有两个子节点:找到该节点右子树中的最小节点(或左子树中的最大节点),用这个最小节点的值替换要删除节点的值,然后删除右子树中的最小节点。

二叉排序树搜索

搜索过程
在二叉排序树中搜索一个特定值的过程如下:

  1. 从根节点开始,将待搜索的值与根节点的值进行比较。
  2. 如果待搜索的值等于根节点的值,则搜索成功,返回该节点。
  3. 如果待搜索的值小于根节点的值,由于二叉排序树的性质,该值只可能在左子树中,因此在左子树中继续进行搜索。
  4. 如果待搜索的值大于根节点的值,该值只可能在右子树中,因此在右子树中继续进行搜索。
  5. 重复上述步骤,直到找到目标节点或者遇到空节点(表示搜索失败)。

代码实现(Python)

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef searchBST(root, val):if root is None or root.val == val:return rootif val < root.val:return searchBST(root.left, val)return searchBST(root.right, val)# 构建示例二叉排序树
root = TreeNode(50)
root.left = TreeNode(30)
root.right = TreeNode(70)
root.left.left = TreeNode(20)
root.left.right = TreeNode(40)
root.right.left = TreeNode(60)
root.right.right = TreeNode(80)# 搜索值为 60 的节点
result = searchBST(root, 60)
if result:print(f"找到了值为 {result.val} 的节点")
else:print("未找到该节点")

复杂度分析

  • 时间复杂度:平均情况下,二叉排序树的高度为 O ( l o g n ) O(log n) O(logn)(其中 n n n 是树中节点的数量),搜索操作的时间复杂度为 O ( l o g n ) O(log n) O(logn)。但在最坏情况下,即二叉排序树退化为链表(例如插入的节点值是有序的),树的高度为 O ( n ) O(n) O(n),搜索操作的时间复杂度会变为 O ( n ) O(n) O(n)
  • 空间复杂度:主要取决于递归调用栈的深度,平均情况下为 O ( l o g n ) O(log n) O(logn),最坏情况下为 O ( n ) O(n) O(n)。如果使用迭代方式实现搜索,空间复杂度可以优化到 O ( 1 ) O(1) O(1)

应用场景
二叉排序树适用于需要频繁进行插入、删除和搜索操作的场景,并且数据集合的规模适中。例如,在一些小型的数据库系统中,用于快速查找特定记录;在编程语言的符号表管理中,用于存储和查找变量名及其相关信息等。

平衡二叉树

定义
平衡二叉树(AVL树)是一种自平衡的二叉搜索树。它满足二叉搜索树的基本性质:对于树中的任意节点,其左子树中所有节点的值都小于该节点的值,右子树中所有节点的值都大于该节点的值。同时,AVL树还额外要求每个节点的左右子树的高度差(平衡因子)的绝对值不超过 1。平衡因子定义为该节点的左子树高度减去右子树高度。

平衡的重要性
通过保持树的平衡,AVL树能够保证在进行插入、删除和查找操作时的时间复杂度始终为 O ( l o g n ) O(log n) O(logn),其中 n n n 是树中节点的数量。如果不进行平衡操作,二叉搜索树可能会退化为链表,此时这些操作的时间复杂度会变为 O ( n ) O(n) O(n)

平衡二叉树查找过程
平衡二叉树的查找过程与普通二叉搜索树的查找过程基本一致:

  1. 从根节点开始,将待查找的值 target 与当前节点的值进行比较。
  2. 如果 target 等于当前节点的值,则查找成功,返回该节点。
  3. 如果 target 小于当前节点的值,则在当前节点的左子树中继续查找。
  4. 如果 target 大于当前节点的值,则在当前节点的右子树中继续查找。
  5. 重复上述步骤,直到找到目标节点或者遇到空节点(表示查找失败)。

示例代码(Python 实现)

# 定义 AVL 树的节点类
class TreeNode:def __init__(self, key):self.key = keyself.left = Noneself.right = Noneself.height = 1  # 节点的高度,初始为 1# 定义 AVL 树类
class AVLTree:# 获取节点的高度def get_height(self, node):if not node:return 0return node.height# 获取节点的平衡因子def get_balance(self, node):if not node:return 0return self.get_height(node.left) - self.get_height(node.right)# 右旋操作def right_rotate(self, y):x = y.leftT2 = x.rightx.right = yy.left = T2y.height = max(self.get_height(y.left), self.get_height(y.right)) + 1x.height = max(self.get_height(x.left), self.get_height(x.right)) + 1return x# 左旋操作def left_rotate(self, x):y = x.rightT2 = y.lefty.left = xx.right = T2x.height = max(self.get_height(x.left), self.get_height(x.right)) + 1y.height = max(self.get_height(y.left), self.get_height(y.right)) + 1return y# 插入节点def insert(self, root, key):if not root:return TreeNode(key)elif key < root.key:root.left = self.insert(root.left, key)else:root.right = self.insert(root.right, key)root.height = 1 + max(self.get_height(root.left), self.get_height(root.right))balance = self.get_balance(root)# 左左情况if balance > 1 and key < root.left.key:return self.right_rotate(root)# 右右情况if balance < -1 and key > root.right.key:return self.left_rotate(root)# 左右情况if balance > 1 and key > root.left.key:root.left = self.left_rotate(root.left)return self.right_rotate(root)# 右左情况if balance < -1 and key < root.right.key:root.right = self.right_rotate(root.right)return self.left_rotate(root)return root# 查找节点def search(self, root, key):if root is None or root.key == key:return rootif key < root.key:return self.search(root.left, key)return self.search(root.right, key)# 测试代码
if __name__ == "__main__":avl_tree = AVLTree()root = Nonekeys = [9, 5, 10, 0, 6, 11, -1, 1, 2]for key in keys:root = avl_tree.insert(root, key)target = 6result = avl_tree.search(root, target)if result:print(f"找到了节点: {result.key}")else:print(f"未找到节点: {target}")

代码解释

  1. TreeNode 类:定义了 AVL 树的节点结构,包含节点的值 key、左右子节点 leftright 以及节点的高度 height
  2. AVLTree 类
    • get_height 方法:用于获取节点的高度。
    • get_balance 方法:用于计算节点的平衡因子。
    • right_rotateleft_rotate 方法:分别实现了右旋和左旋操作,用于调整树的平衡。
    • insert 方法:插入新节点,并在插入后检查树的平衡情况,必要时进行旋转操作以保持树的平衡。
    • search 方法:实现了查找功能,通过递归的方式在树中查找目标节点。
  3. 测试部分:创建一个 AVL 树,插入一系列节点,然后查找目标节点 6,并输出查找结果。

通过这种方式,我们可以在平衡二叉树中高效地进行查找操作。

复杂度分析

  • 时间复杂度
    • 平均情况:在平衡二叉树(AVL树)中,由于它始终保持着左右子树高度差不超过 1 的平衡特性,树的高度 h h h 始终维持在 O ( log ⁡ n ) O(\log n) O(logn) 级别,其中 n n n 是树中节点的数量。而查找操作需要从根节点开始,沿着一条路径向下搜索,经过的节点数最多为树的高度。因此,平均情况下平衡二叉树查找操作的时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)。例如,当树中有 1024 个节点时,树的高度大约为 log ⁡ 2 1024 = 10 \log_2{1024}=10 log21024=10,查找操作最多只需比较 10 次。
    • 最坏情况:由于平衡二叉树严格保证了树的平衡性,即使在最坏情况下,树的高度依然是 O ( log ⁡ n ) O(\log n) O(logn),所以查找操作的时间复杂度仍然是 O ( log ⁡ n ) O(\log n) O(logn)。这与普通二叉搜索树不同,普通二叉搜索树在最坏情况下(退化为链表)查找时间复杂度会达到 O ( n ) O(n) O(n)

空间复杂度

  • 平衡二叉树查找操作的空间复杂度主要取决于递归调用栈的深度。在递归查找过程中,每次递归调用会在栈上分配一定的空间。由于查找路径的长度最长为树的高度,而树的高度为 O ( log ⁡ n ) O(\log n) O(logn),所以查找操作的空间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)。如果采用迭代方式实现查找,空间复杂度可以优化到 O ( 1 ) O(1) O(1),因为只需要使用常数级的额外空间来记录当前节点的位置。

适合使用的场景

  • 当数据集合需要频繁进行插入、删除和查找操作时,平衡二叉树是一个不错的选择。例如,在数据库的索引系统中,数据会不断地被插入和删除,同时也需要快速地查找特定的数据记录。平衡二叉树能够在保证插入和删除操作相对高效的同时,确保查找操作的时间复杂度始终为 O ( log ⁡ n ) O(\log n) O(logn)

  • 对于一些对查找速度要求极高的应用,如搜索引擎的缓存系统、实时数据处理系统等,平衡二叉树的高效查找性能能够满足这些场景的需求。以搜索引擎的缓存系统为例,需要快速地查找缓存中是否存在某个网页的信息,平衡二叉树可以在较短的时间内完成查找操作,提高系统的响应速度。

  • 如果只需要快速查找特定的数据,而不需要数据始终保持严格的有序性,平衡二叉树可以很好地满足需求。例如,在一些游戏的物品管理系统中,需要快速查找某个物品的属性信息,平衡二叉树可以高效地实现这一功能,而不需要像排序数组那样始终保持数据的严格有序。

红黑树

定义
红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是红色或黑色。通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。红黑树必须满足以下五个性质:

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL节点,空节点)是黑色。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的。
  5. 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。

示例
以下是一个简单的红黑树示例(为方便表示,这里用括号内的 R 表示红色节点,B 表示黑色节点):

        (50B)/      \(30R)      (70R)/    \      /    \
(20B)  (40B) (60B)  (80B)

在这个红黑树中,根节点 50 是黑色,红色节点 30 和 70 的子节点都是黑色,并且从每个节点到其所有后代叶节点的简单路径上黑色节点的数量相同。

红黑树查找

查找过程
红黑树的查找过程与普通二叉搜索树的查找过程基本相同,具体步骤如下:

  1. 从根节点开始,将待查找的值与根节点的值进行比较。
  2. 如果待查找的值等于根节点的值,则查找成功,返回该节点。
  3. 如果待查找的值小于根节点的值,由于红黑树也是二叉搜索树,该值只可能在左子树中,因此在左子树中继续进行查找。
  4. 如果待查找的值大于根节点的值,该值只可能在右子树中,因此在右子树中继续进行查找。
  5. 重复上述步骤,直到找到目标节点或者遇到空节点(表示查找失败)。
代码实现(Python)
class TreeNode:def __init__(self, val=0, color='R', left=None, right=None):self.val = valself.color = colorself.left = leftself.right = rightdef searchRedBlackTree(root, val):if root is None or root.val == val:return rootif val < root.val:return searchRedBlackTree(root.left, val)return searchRedBlackTree(root.right, val)# 构建简单红黑树示例(这里只是简单构建,未完整体现插入调整逻辑)
root = TreeNode(50, 'B')
root.left = TreeNode(30, 'R')
root.right = TreeNode(70, 'R')
root.left.left = TreeNode(20, 'B')
root.left.right = TreeNode(40, 'B')
root.right.left = TreeNode(60, 'B')
root.right.right = TreeNode(80, 'B')# 查找值为 60 的节点
result = searchRedBlackTree(root, 60)
if result:print(f"找到了值为 {result.val} 的节点")
else:print("未找到该节点")

复杂度分析

  • 时间复杂度:由于红黑树是接近平衡的,其高度始终保持在 O ( l o g n ) O(log n) O(logn) 级别(其中 n n n 是树中节点的数量),因此查找操作的时间复杂度为 O ( l o g n ) O(log n) O(logn)。这意味着在大规模数据集合中,红黑树查找能够保持较高的效率。
  • 空间复杂度:主要取决于递归调用栈的深度,平均情况下为 O ( l o g n ) O(log n) O(logn),最坏情况下也为 O ( l o g n ) O(log n) O(logn)。如果使用迭代方式实现查找,空间复杂度可以优化到 O ( 1 ) O(1) O(1)

应用场景
红黑树在许多领域都有广泛的应用,以下是一些常见的场景:

  • 编程语言的标准库:如 Java 的 TreeMap 和 TreeSet、C++ 的 STL 中的 map 和 set 等,利用红黑树的特性实现了有序的键值对存储和快速查找功能。
  • 操作系统的内存管理:在操作系统中,红黑树可用于管理内存块的分配和释放,通过红黑树可以快速查找合适的内存块。
  • 数据库索引:在数据库系统中,红黑树可以作为索引结构,提高数据的查找效率,特别是对于需要频繁进行插入、删除和查找操作的场景。

B 树和B+数查询

B树

定义
B 树是一种自平衡的多路搜索树,它能够保持数据有序,并且允许在对数时间内进行插入、删除和查找操作。B 树的每个节点可以有多个子节点(通常大于 2),并且所有叶子节点都在同一层。一个 m 阶的 B 树需要满足以下条件:

  • 每个节点最多有 m 个子节点。
  • 除根节点和叶子节点外,每个节点至少有 ⌈ m / 2 ⌉ \lceil m/2 \rceil m/2 个子节点。
  • 根节点至少有 2 个子节点(除非它是叶子节点)。
  • 所有叶子节点都在同一层。
  • 每个节点中的键值按升序排列,并且键值的数量比子节点数量少 1。

示例
下面是一个 3 阶 B 树的简单示例:

          [30, 60]/    |    \[10, 20] [40, 50] [70, 80]

在这个 3 阶 B 树中,根节点包含两个键值 30 和 60,有三个子节点。每个子节点包含两个键值,并且键值是有序排列的。

B 树查找过程

  1. 从根节点开始,将待查找的值与根节点中的键值进行比较。
  2. 如果待查找的值等于根节点中的某个键值,则查找成功,返回该键值所在的位置。
  3. 如果待查找的值小于根节点中的某个键值,则进入该键值左侧的子节点继续查找。
  4. 如果待查找的值大于根节点中的所有键值,则进入最右侧的子节点继续查找。
  5. 重复上述步骤,在子节点中继续比较和查找,直到找到目标键值或者到达叶子节点。如果到达叶子节点仍未找到目标键值,则查找失败。

代码实现(Python 伪代码)

class BTreeNode:def __init__(self, is_leaf=False):self.is_leaf = is_leafself.keys = []self.child = []class BTree:def __init__(self, m):self.root = BTreeNode(is_leaf=True)self.m = mdef search(self, key):return self._search(self.root, key)def _search(self, node, key):i = 0while i < len(node.keys) and key > node.keys[i]:i += 1if i < len(node.keys) and key == node.keys[i]:return nodeif node.is_leaf:return Nonereturn self._search(node.child[i], key)# 示例使用
b_tree = BTree(3)
# 这里省略插入节点的代码
result = b_tree.search(40)
if result:print("找到了键值 40")
else:print("未找到键值 40")

复杂度分析

  • 时间复杂度:B 树的高度 h h h 与节点数量 n n n 的关系为 h = O ( log ⁡ ⌈ m / 2 ⌉ n ) h = O(\log_{\lceil m/2 \rceil} n) h=O(logm/2n),其中 m m m 是 B 树的阶数。因此,B 树查找操作的时间复杂度为 O ( log ⁡ ⌈ m / 2 ⌉ n ) O(\log_{\lceil m/2 \rceil} n) O(logm/2n),在实际应用中,由于 m m m 通常较大,查找效率较高。
  • 空间复杂度:主要取决于树中节点的数量,空间复杂度为 O ( n ) O(n) O(n)

应用场景
B 树常用于文件系统和数据库系统中,因为它可以有效减少磁盘 I/O 次数。在这些系统中,数据通常存储在磁盘上,磁盘 I/O 操作的时间开销较大,B 树的多路特性使得每次磁盘 I/O 可以读取或写入多个键值,从而提高了系统的性能。

B + 树

定义
B + 树是 B 树的一种变体,它与 B 树的主要区别在于:

  • 所有的数据都存储在叶子节点中,非叶子节点只存储索引信息。
  • 叶子节点之间通过指针相连,形成一个有序链表。

示例
以下是一个简单的 B + 树示例:

         [30, 60]/      \[10, 20]    [40, 50, 70, 80]|         /   |   \10       40   50   70 - 80 (叶子节点相连)

在这个 B + 树中,非叶子节点只包含索引键值 30 和 60,所有的数据(10、20、40、50、70、80)都存储在叶子节点中,并且叶子节点通过指针形成了有序链表。

B + 树查找过程

  • 精确查找:从根节点开始,按照与 B 树类似的方式,将待查找的值与非叶子节点中的键值进行比较,确定进入哪个子节点继续查找,直到到达叶子节点。在叶子节点中线性查找目标键值。
  • 范围查找:先通过精确查找找到范围的起始键值所在的叶子节点,然后利用叶子节点之间的指针顺序遍历,直到找到范围的结束键值或超出范围。

代码实现(Python 伪代码)

class BPlusTreeNode:def __init__(self, is_leaf=False):self.is_leaf = is_leafself.keys = []self.child = []self.next = Noneclass BPlusTree:def __init__(self, m):self.root = BPlusTreeNode(is_leaf=True)self.m = mdef search(self, key):node = self.rootwhile not node.is_leaf:i = 0while i < len(node.keys) and key > node.keys[i]:i += 1node = node.child[i]for k in node.keys:if k == key:return Truereturn False# 示例使用
b_plus_tree = BPlusTree(3)
# 这里省略插入节点的代码
result = b_plus_tree.search(50)
if result:print("找到了键值 50")
else:print("未找到键值 50")

复杂度分析

  • 时间复杂度:与 B 树类似,B + 树的查找操作时间复杂度也为 O ( log ⁡ ⌈ m / 2 ⌉ n ) O(\log_{\lceil m/2 \rceil} n) O(logm/2n)。对于范围查找,由于叶子节点之间有指针相连,时间复杂度为 O ( k + log ⁡ ⌈ m / 2 ⌉ n ) O(k + \log_{\lceil m/2 \rceil} n) O(k+logm/2n),其中 k k k 是范围内键值的数量。
  • 空间复杂度:同样为 O ( n ) O(n) O(n),主要用于存储树中的节点。

应用场景
B + 树在数据库系统中应用广泛,如 MySQL 的 InnoDB 存储引擎默认使用 B + 树作为索引结构。因为 B + 树的结构非常适合范围查询,并且由于所有数据都存储在叶子节点,使得数据库的插入、删除和查找操作更加高效和稳定。同时,叶子节点的有序链表结构也方便进行顺序访问,提高了数据的读取效率。

分块查找

也称为索引顺序查找,它是一种介于顺序查找和二分查找之间的查找方法。以下从基本思想、实现步骤、复杂度分析、优缺点和适用场景等方面详细介绍:

基本思想
分块查找将一个线性表分成若干个块,每个块内的元素可以是无序的,但块与块之间是有序的,即后一个块中所有元素的值都大于前一个块中所有元素的值。同时,还需要建立一个索引表,索引表中记录了每个块的最大关键字以及该块在原线性表中的起始位置,索引表是按关键字有序排列的。

实现步骤
分块查找主要分为两步:

  1. 确定待查元素所在的块:使用二分查找或顺序查找在索引表中查找,根据索引表中记录的块的最大关键字,确定待查元素可能存在于哪个块中。
  2. 在块内查找元素:在确定的块中使用顺序查找的方法查找待查元素。

示例及代码实现
假设我们有一个线性表 [22, 12, 13, 8, 9, 20, 33, 42, 44, 38, 24, 48],将其分成 3 个块,每个块有 4 个元素。
索引表为 [(22, 0), (44, 4), (48, 8)],其中每个元组的第一个元素是块的最大关键字,第二个元素是块在原线性表中的起始位置。

以下是 Python 代码实现:

def block_search(arr, index_table, target):# 第一步:在索引表中确定所在块block_index = -1for i in range(len(index_table)):if target <= index_table[i][0]:block_index = ibreakif block_index == -1:return -1# 第二步:在块内进行顺序查找start = index_table[block_index][1]if block_index == len(index_table) - 1:end = len(arr)else:end = index_table[block_index + 1][1]for i in range(start, end):if arr[i] == target:return ireturn -1# 线性表
arr = [22, 12, 13, 8, 9, 20, 33, 42, 44, 38, 24, 48]
# 索引表
index_table = [(22, 0), (44, 4), (48, 8)]
target = 24
result = block_search(arr, index_table, target)
if result != -1:print(f"元素 {target} 在数组中的索引是 {result}")
else:print(f"未找到元素 {target}")

复杂度分析

  • 时间复杂度:设线性表长度为 n n n,分成 b b b 个块,每个块有 s s s 个元素( n = b × s n = b \times s n=b×s)。在索引表中查找块的时间复杂度,如果使用顺序查找为 O ( b ) O(b) O(b),使用二分查找为 O ( log ⁡ 2 b ) O(\log_2b) O(log2b);在块内进行顺序查找的时间复杂度为 O ( s ) O(s) O(s)。所以,分块查找的平均时间复杂度为 O ( b + s ) O(b + s) O(b+s) O ( log ⁡ 2 b + s ) O(\log_2b + s) O(log2b+s)。当 s = n s = \sqrt{n} s=n 时,时间复杂度达到最优,为 O ( n ) O(\sqrt{n}) O(n )
  • 空间复杂度:主要是索引表占用的额外空间,为 O ( b ) O(b) O(b),其中 b b b 是块的数量。

优缺点

  • 优点
    • 对数据的要求相对较低,不需要像二分查找那样数据必须完全有序,只需要块间有序、块内可以无序,这在数据动态变化时比较方便维护。
    • 查找效率比顺序查找高,尤其是在数据量较大时。
  • 缺点:需要额外的存储空间来存储索引表,增加了空间开销。

适用场景

  • 数据量较大且分布不均匀:当数据量较大,且数据的分布不太规则时,分块查找可以通过合理分块,提高查找效率。
  • 数据动态变化:由于分块查找只要求块间有序,在数据插入、删除时,只需要调整相应块内的数据,对整体的块间顺序影响较小,相比于完全有序的数据结构更易于维护。

斐波那契查找和插值查找在特定场景下有其独特的优势,但整体而言,它们不如顺序查找、二分查找等方法常用,以下为你详细分析:

斐波那契查找和插值查找

斐波那契查找

  • 原理:斐波那契查找是在二分查找的基础上,利用斐波那契数列来确定分割点。它通过斐波那契数列的特性,将有序数组分成两部分进行查找,使得分割点更偏向于数据分布较密集的一侧。
  • 不常用的原因
    • 实现复杂度相对较高:需要对斐波那契数列有一定的了解和处理,要生成斐波那契数列并根据其规律进行查找区间的划分,相较于二分查找,实现起来更复杂,代码编写和理解成本更高。
    • 适用场景受限:它主要适用于对数据存储在磁盘等外部存储设备上的查找场景,因为它在某些情况下可以减少磁盘 I/O 次数。但在现代计算机系统中,内存访问速度有了极大提升,且磁盘存储设备的性能也不断改进,这种减少磁盘 I/O 的优势不再那么明显。
  • 常用场景:在一些对内存使用和数据分布有特殊要求的嵌入式系统或特定算法中可能会使用斐波那契查找。例如,在某些资源受限的嵌入式设备中,当需要对有序数据进行查找时,斐波那契查找可以在一定程度上平衡查找效率和资源消耗。

插值查找

  • 原理:插值查找是对二分查找的一种改进,它根据待查找关键字在数据集中的大致位置,动态地计算分割点。通过估计目标值在数组中的位置,插值查找可以更快地缩小查找范围,尤其适用于数据均匀分布的有序数组。
  • 不常用的原因
    • 对数据分布要求高:插值查找的效率依赖于数据的均匀分布。如果数据分布不均匀,插值查找的性能可能会大幅下降,甚至不如二分查找。在实际应用中,很多数据集的数据分布并不均匀,这限制了插值查找的广泛使用。
    • 边界情况处理复杂:当数据分布极端不均匀时,插值查找计算出的分割点可能会超出合理范围,需要进行额外的边界检查和处理,增加了算法的复杂度。
  • 常用场景:在数据均匀分布且数据量较大的场景下,插值查找能发挥出明显的优势。例如,在一些科学计算、地理信息系统等领域,数据可能具有较好的均匀性,此时使用插值查找可以显著提高查找效率。

相关文章:

常用查找算法整理(顺序查找、二分查找、哈希查找、二叉排序树查找、平衡二叉树查找、红黑树查找、B树和B+树查找、分块查找)

常用的查找算法&#xff1a; 顺序查找&#xff1a;最简单的查找算法&#xff0c;适用于无序或数据量小的情况&#xff0c;逐个元素比较查找目标值。二分查找&#xff1a;要求数据有序&#xff0c;通过不断比较中间元素与目标值&#xff0c;将查找范围缩小一半&#xff0c;效率…...

自动化办公|xlwings 数据类型和转换

xlwings 数据类型和转换&#xff1a;Python 与 Excel 的桥梁 在使用 xlwings 进行 Python 和 Excel 数据交互时&#xff0c;理解两者之间的数据类型对应关系至关重要。本篇将详细介绍 Python 数据类型与 Excel 数据类型的对应关系&#xff0c;以及如何进行数据类型转换。 一、…...

Edge浏览器清理主页

我们都知道&#xff0c;Microsoft Edge浏览器是微软创造的搜索浏览器&#xff0c;Windows10、11自带。但是你可以看到&#xff0c;每次你打开Edge浏览器的时候都可以看到许多的广告&#xff0c;如图&#xff1a; 导致打开Edge浏览器的时候会遭受卡顿&#xff0c;广告骚扰&#…...

RedHat8安装postgresql15和 postgis3.4.4记录及遇到的问题总结

安装包对照版本参考 UsersWikiPostgreSQLPostGIS – PostGIS 如果Red Hat系统上有旧版本的PostgreSQL需要卸载 在较新的Red Hat版本&#xff0c;使用dnf包管理器卸载&#xff1a;sudo dnf remove postgresql-server postgresql 旧版本&#xff0c;使用yum包管理器卸载 sudo y…...

Java 大视界 -- 绿色大数据:Java 技术在节能减排中的应用与实践(90)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

Python 文本探秘:正则表达式的易错迷宫穿越 -- 7. 正则表达式

正则表达式是 Python 中处理文本的强大武器&#xff0c;但它复杂的语法和规则构成了一个易错迷宫。本文深入剖析了正则表达式模式编写的错误、匹配规则的误解、性能优化的忽视等问题。通过大量的文本处理实例&#xff0c;展示了错误的正则表达式使用方式以及正确的解决方案。帮…...

Ubuntu22.04通过Docker部署Jeecgboot

程序发布环境包括docker、mysql、redis、maven、nodejs、npm等。 一、安装docker 1、用如下命令卸载旧Docker: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done 2、安装APT环境依赖包…...

数据结构 二叉树

一、⼆叉树的定义 ⼆叉树是⼀种特殊的树型结构&#xff0c;它的特点是每个结点⾄多只有2棵⼦树&#xff08;即⼆叉树中不存在度⼤于2的结点&#xff09;&#xff0c;并且⼆叉树的⼦树有左右之分&#xff0c;其次序不能任意颠倒。 ⼆叉的意思是这种树的每⼀个结点最多只有两个孩…...

基于python sanic框架,使用Nacos进行微服务管理

微服务软件系统构建方式,已经很普及了,通过开源的sanic进行微服务管理,便捷,技术也比较成熟,而在项目实际应用过程中,微服务类型不仅有java的,还有nodejs、python等,尤其是结合算法模型构建的python接口,需要在Nacos进行注册管理。本文内容耗时2天踏坑,亲测一切ok。 …...

hbase合并队列超长问题分析

问题现象 hbase集群合并队列超长,有节点上合并任务已经运行超过1天未结束,合并队列总长不断增加。 问题分析 参数配置: 配置参数默认值含义hbase.hregion.memstore.flush.size128MMemStore达到该值会Flush成StoreFilehbase.hregion.memstore.block.multiplier4当region中…...

【设计模式】【行为型模式】解释器模式(Interpreter)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f3b5; 当你的天空突…...

DeepSeek-R1 蒸馏 Qwen 和 Llama 架构 企业级RAG知识库

“DeepSeek-R1的输出&#xff0c;蒸馏了6个小模型”意思是利用DeepSeek-R1这个大模型的输出结果&#xff0c;通过知识蒸馏技术训练出6个参数规模较小的模型&#xff0c;以下是具体解释&#xff1a; - **知识蒸馏技术原理**&#xff1a;知识蒸馏是一种模型压缩技术&#xff0c;核…...

无人机航迹规划:互联银行系统优化(Connected Banking System Optimizer,CBSO)求解无人机路径规划MATLAB

一、互联银行系统优化算法 互联银行系统优化&#xff08;Connected Banking System Optimizer&#xff0c;CBSO&#xff09;算法是2024年由Mehrdad Nemati等人提出的一种智能优化算法&#xff0c;其灵感来源于银行系统之间的连接和交易过程。在银行系统中&#xff0c;核心银行…...

学习web数据埋点

什么是埋点&#xff0c;以及为什么需要埋点 通过代码主动收集用户行为数据&#xff08;如点击、浏览、停留时长等&#xff09;&#xff0c;用于数据分析驱动产品优化。 一、前端埋点 在客户端&#xff08;浏览器、移动端应用&#xff09;直接采集用户行为数据&#xff0c;通…...

Windows 11 安装 Docker

1.以管理员身份打开 Windows PowerShell 2.执行下面三行命令来启动WSL和虚拟机平台 dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestartdism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norest…...

深度学习框架探秘|Keras:深度学习的魔法钥匙

一、引言&#xff1a;深度学习浪潮中的 Keras 前面的文章我们探秘了深度学习框架中的两大明星框架 —— TensorFlow 和 PyTorch 以及 两大框架的对比 在深度学习的众多框架中&#xff0c;还有一款框架备受开发者们的喜爱 —— Keras 。它就像是一位贴心的助手&#xff0c;为我…...

HTML【详解】input 标签

input 标签主要用于接收用户的输入&#xff0c;随 type 属性值的不同&#xff0c;变换其具体功能。 通用属性 属性属性值功能name字符串定义输入字段的名称&#xff0c;在表单提交时&#xff0c;服务器通过该名称来获取对应的值disabled布尔值禁用输入框&#xff0c;使其无法被…...

在vscode中拉取gitee里的项目并运行

拉取项目: 方法一:vscode点击查看--->终端(或者直接通过快捷键ctrol+ `打开) 在终端内通过cd命令定位到你想存放项目的文件夹 例如:cd h: 通过命令:git clone 地址 例如:git clone newbee-mall-vue-app: 前端代码 等待拉取完成即可在对应文件夹下看到项目啦 方…...

Spring Cloud微服务

一、定义 微服务&#xff0c;又叫微服务架构&#xff0c;也就是分布式架构&#xff0c;是软件架构的一种方式。它将一个大的单体架构应用拆分成一系列按业务领域划分模块的、小的自治服务。 如开发部有很多任务&#xff0c;如果把任务给了一个组的话&#xff0c;效率肯定会降低…...

打破AI黑盒,拥抱开源力量:基于openGauss+DeepSeek的本地知识库,打造你的专属AI助手!

引言&#xff1a;什么是RAG和LLM&#xff1f; LLM (Large Language Model&#xff0c;大语言模型): 就像 ChatGPT 这样的 AI 模型&#xff0c;拥有强大的语言理解和生成能力&#xff0c;但它们的知识局限于训练数据&#xff0c;且可能产生“幻觉”&#xff08;即生成不准确的信…...

如何在 IntelliJ IDEA 中使用 Bito AI 插件

如何在 IntelliJ IDEA 中使用 Bito AI 插件 Bito: On-Demand AI Code Reviews Bito AI 插件是一个智能开发工具&#xff0c;能够帮助开发者提升编码效率&#xff0c;自动化生成代码、注释、单元测试等。本文将详细介绍 Bito AI 插件在 IntelliJ IDEA 中的使用方法&#xff0c…...

用xml配置spring, bean标签有哪些属性?

用xml配置spring, bean标签有哪些属性? 在Spring框架中&#xff0c;使用XML配置文件时&#xff0c;<bean>标签用于定义一个Bean。以下是一些常用的<bean>标签属性&#xff1a; 1. class 描述&#xff1a;指定Bean的类名。示例&#xff1a;<bean id"myBe…...

微信小程序中缓存数据全方位解惑

微信小程序中缓存数据全方位解惑 微信小程序中的数据缓存是提升用户体验和优化性能的重要手段&#xff0c;跟电脑浏览器中的Local Storage的性质一样。以下是关于微信小程序数据缓存的相关知识点和示例的详细介绍&#xff1a; 1. 数据缓存的类型 微信小程序提供了两种数据缓…...

物联网平台-分布式的设备接入与管理系统

乐吾乐物联网平台是由乐吾乐自主研发的一款分布式的设备接入与管理系统&#xff0c;专为满足不断增长的设备接入和数据处理需求而设计。平台集数据采集、分析、监控、告警和通知等功能于一体&#xff0c;并融合了乐吾乐大屏可视化和乐吾乐3D数字孪生技术&#xff0c;帮助用户快…...

ABP - 事件总线之分布式事件总线

ABP - 事件总线之分布式事件总线 1. 分布式事件总线的集成1.2 基于 RabbitMQ 的分布式事件总线 2. 分布式事件总线的使用2.1 发布2.2 订阅2.3 事务和异常处理 3. 自己扩展的分布式事件总线实现 事件总线可以实现代码逻辑的解耦&#xff0c;使代码模块之间功能职责更清晰。而分布…...

ComfyUI流程图生图原理详解

一、引言 ComfyUI 是一款功能强大的工具&#xff0c;在图像生成等领域有着广泛应用。本文补充一点ComfyUI 的安装与配置过程遇到的问题&#xff0c;并深入剖析图生图过程及相关参数&#xff0c;帮助读者快速入门并深入理解其原理。 二、ComfyUI 的安装与配置中遇到的问题 &a…...

洛谷 P3660 USACO17FEB Why Did the Cow Cross the Road III 题解

题意 有一个圆&#xff0c;圆周上按顺时针方向给出 2 n 2n 2n个点。第 i i i个点的颜色是 c o l o r i color_i colori​&#xff0c;其中数据保证 1 ≤ c o l o r i ≤ n 1\le color_i\le n 1≤colori​≤n&#xff0c;而且每种不同的颜色有且只有两个点。不存在位置重叠的点…...

kubekey一键部署k8s高可用与kubesphere

kubekey一键安装k8s与kubesphere还是蛮方便的&#xff0c;kubesphere官网上面也提到了高可用安装的一些事宜&#xff0c;但是没有涉及到kubesphere资深的redis的系统的部署问题&#xff0c;本文简单给出对应配置&#xff0c;其实这个配置在kubephere的cluster-configuration.ya…...

SwiftUI 5.0 中宝藏视图修改器 containerRelativeFrame 趣谈(下)

概览 小伙伴们都知道,为了将 SwiftUI 中多如牛毛的视图井然有序、有条不紊的组织起来,我们必须借助容器(Container)伏虎降龙般地威力。而如何最大限度的让容器中的子视图能根据容器尺寸安排自己的空间,则需要一些技术手段来洞幽察微。 在过去,我们往往使用 GeometryRead…...

ElasticSearch基础和使用

ElasticSearch基础 1 初识ES相关组件 &#xff08;1&#xff09;Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容。Elasticsearch结合kibana、Logstash、Beats组件 也就是elastic stack&#xff08;ELK&#xff09; 广泛应…...

我用 Cursor 开发了一款个人小记系统

https://note.iiter.cn 项目背景 在日常工作和学习中,我们经常需要快速记录一些想法、收藏一些有用的链接或者保存一些重要的文本、图片内容。虽然市面上已经有很多笔记软件,但我想要一个更轻量、更简单的工具,专注于快速记录和智能检索。于是我开发了这款个人小记系统。 系统…...

如何使用Three.js制作3D月球与星空效果

目录 1. 基本设置2. 创建星空效果3. 创建月球模型4. 添加中文3D文字5. 光照与相机配置6. 动画与控制7. 响应式布局8. 结语 在本文中&#xff0c;我们将一起学习如何利用Three.js实现一个3D月球与星空的效果&#xff0c;并添加一些有趣的元素&#xff0c;比如中文3D文字和互动功…...

DeepSeek接入网络安全领域,AI高效驱动,重新定义网络防御边界!

DeepSeek新一代模型的发布&#xff0c;标志着AI大模型的应用将逐步走向普及&#xff0c;并加速AI技术在各行业的赋能与全面落地。在科技日新月异的今天&#xff0c;AI技术凭借其强大的数据处理与分析能力&#xff0c;已成为推动社会进步的核心动力。 在网络安全领域&#xff0…...

【动态规划】斐波那契数列模型

目录 ​动态规划 动态规划的基本步骤 1137. 第 N 个泰波那契数 - 力扣&#xff08;LeetCode&#xff09; 算法分析 算法代码 算法代码 面试题 08.01. 三步问题 - 力扣&#xff08;LeetCode&#xff09; 算法分析 算法代码 优化 746. 使用最小花费爬楼梯 - 力扣&#x…...

Spring中的IOC详解

文章目录 IOC IOC容器的工作原理Bean的生命周期Bean的自动装配 AutowiredResourceInject 使用Spring底层组件 IOC Spring的核心之一是IOC&#xff0c;IOC全称为Inversion of Control&#xff0c;中文译为控制反转&#xff0c;是面向对象编程中的一种设计原则&#xff0c;可…...

深挖vue3基本原理之七 —— 功能模块的深度技术解析

Vue 3 四个核心功能模块的深度技术解析 一、Effect 调度系统&#xff1a;同步/异步任务队列 实现原理 // runtime-core/src/scheduler.ts const queue: (EffectJob | null)[] [] let isFlushing false const resolvedPromise Promise.resolve()function queueJob(job: Ef…...

数据结构 day 07

数据结构 day07 7. 树7.3. 层次遍历代码实现 8. 查询算法8.1. 顺序查找 seqSearch代码实现 8.2. 二分法查找 binarySearch代码实现 8.2. 分块查找 blockSearch代码实现 8.3. 哈希表 hash 9. 排序算法9.1. 冒泡排序 bubSort代码实现 9.2. 选择排序 selSort代码实现 9.3. 插入排序…...

《代码随想录》刷题笔记——回溯篇【java实现】

文章目录 组合组合总和 III电话号码的字母组合组合总和组合总和II思路代码实现 分割回文串※思路字符串分割回文串判断效率优化※ 复原 IP 地址优化版本 子集子集 II使用usedArr辅助去重不使用usedArr辅助去重 递增子序列※全排列全排列 II重新安排行程题意代码 N 皇后解数独直…...

React:初识React

React是什么&#xff1f; React是由Meta公司研发&#xff0c;也就是Facebook的公司&#xff08;马克扎克伯格这个见人&#xff09;研发的构建Web和原生交互界面的库 不仅可以写网页&#xff0c;还可以写苹果和安卓上面的app React的优势&#xff1a; React也是前端里最流行的…...

全面理解-c++中的内存布局

在 C 中&#xff0c;程序的内存布局指的是程序运行时&#xff0c;代码和数据在内存中的组织和分布方式。一般来说&#xff0c;C 程序的内存可以划分为以下几个主要区域&#xff1a; 1. 代码段&#xff08;Text Segment&#xff0c;也称为 .text 段&#xff09; 存储内容&…...

百度沈抖:传统云计算不再是主角,智能计算呼唤新一代“操作系统”

Create 2024 百度AI开发者大会 4月16日&#xff0c;Create 2024 百度AI开发者大会在深圳召开。期间&#xff0c;百度集团执行副总裁、百度智能云事业群总裁沈抖正式发布新一代智能计算操作系统——万源&#xff0c;通过对AI原生时代的智能计算平台进行抽象与封装设计&#xff…...

【银河麒麟高级服务器操作系统】服务器卡死后恢复系统日志丢失-分析及处理全过程

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://document.kylinos.cn 服务器环境以及配置 【机型】 处理器&#xff…...

VSCode Error Lens插件介绍(代码静态检查与提示工具)(vscode插件)

文章目录 VSCode Error Lens 插件介绍**功能概述****开发背景****使用方法****适用场景** VSCode Error Lens 插件介绍 功能概述 Error Lens 是一款增强 VS Code 错误提示的扩展工具&#xff0c;通过 内联显示错误和警告信息&#xff0c;直接定位代码问题&#xff0c;提升开发…...

ffmpeg configure 研究1-命令行参数的分析

author: hjjdebug date: 2025年 02月 14日 星期五 17:16:12 CST description: ffmpeg configure 研究1 ./configure 命令行参数的分析 文章目录 1 configure 对命令行参数的分析,在4019行1.1 函数名称: is_in1.2. 函数名称: enable1.3. 函数名称: set_all 2 执行退出判断的关键…...

如何调整 Nginx工作进程数以提升性能

&#x1f3e1;作者主页&#xff1a;点击&#xff01; Nginx-从零开始的服务器之旅专栏&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年2月15日14点20分 Nginx 的工作进程数&#xff0…...

分布式 NewSQL 数据库(TiDB)

TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议&#xff0c;具有数据强一致的高可用特性&#xff0c;是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据库。 TiDB是 PingCAP公司自主设计、研发的开源分布式关系型数据…...

try learning-git-branching

文章目录 mergerebase分离 HEAD相对引用利用父节点branch -f 撤销变更cherry-pick交互式 rebase只取一个提交记录提交的技巧rebase 在上一次提交上amendcherry-pick 在上一次提交上 amend tag多分支 rebase两个parent节点纠缠不清的分支偏离的提交历史锁定的Main推送主分支合并…...

【kafka系列】Kafka事务的实现原理

目录 1. 事务核心组件 1.1 幂等性生产者&#xff08;Idempotent Producer&#xff09; 1.2 事务协调器&#xff08;TransactionCoordinator&#xff09; 1.3 事务日志&#xff08;Transaction Log&#xff09; 2. 事务执行流程 2.1 事务初始化 2.2 发送消息 2.3 事务提…...

数据结构6

一、哈希散列--通讯录查找 #include "hash.h" #include <stdio.h> #include <stdlib.h> #include <string.h>//int *a[10];int hash_function(char key) {if (key > a && key < z){return key - a;}else if (key > A && …...

Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用

Flutter 的 Widget Key 提议大调整&#xff1f;深入聊一聊 Key 的作用 在 Flutter 里&#xff0c;Key 对象存在的目的主要是区分和维持 Widget 的状态&#xff0c;它是控件在渲染树里的「复用」标识之一&#xff0c;这一点在之前的《深入 Flutter 和 Compose 在 UI 渲染刷新时…...