常用查找算法整理(顺序查找、二分查找、插值查找、斐波那契查找、哈希查找、二叉排序树查找、平衡二叉树查找、红黑树查找、B树和B+树查找、分块查找)
常用的查找算法:
- 顺序查找:最简单的查找算法,适用于无序或数据量小的情况,逐个元素比较查找目标值。
- 二分查找:要求数据有序,通过不断比较中间元素与目标值,将查找范围缩小一半,效率较高。
- 插值查找:基于二分查找的改进,基于线性插值思想,根据目标值与数组最值关系确定查找位置,数据均匀时效率优于二分查找。
- 斐波那契查找:基于二分查找的改进,利用斐波那契数列划分有序数组查找区间, 在特定硬件及外存数据查找有优势。
- 哈希查找:利用哈希函数将键值映射到特定存储位置,能在较短时间内实现查找,常用于数据量较大且对查找速度要求高的场景。
- 二叉排序树查找:基于二叉排序树数据结构,左子树节点值小于根节点值,右子树节点值大于根节点值,通过比较和递归进行查找。
- 平衡二叉树查找:如AVL树、红黑树等,在二叉排序树基础上保持平衡,提高查找效率,适用于数据动态变化频繁的场景。
- 红黑树查找:红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是红色或黑色。经常用于编程语言的标准库、操作系统的内存管理、数据库索引。
- B树和B+树查找:常用于文件系统和数据库系统的索引结构,能高效处理大量数据的查找和范围查询。
- 分块查找:将数据分块,块内无序但块间有序,先确定块再在块内查找,性能介于顺序查找和二分查找之间。
- 斐波那契查找和插值查找在特定场景下有其独特的优势,但整体而言,它们不如顺序查找、二分查找等方法常用,
顺序查找
基本概念
顺序查找,也称为线性查找,是在一个数据集合中从第一个元素开始,逐个比较元素,直到找到目标元素或遍历完整个集合为止的查找方法。它适用于无序的线性表,也可用于有序的线性表。
算法实现
- 一般实现步骤
- 从数据集合的第一个元素开始。
- 将当前元素与要查找的目标元素进行比较。
- 如果当前元素等于目标元素,则查找成功,返回当前元素的位置。
- 如果当前元素不等于目标元素,则继续比较下一个元素。
- 重复上述步骤,直到找到目标元素或者遍历完整个数据集合。如果遍历完整个集合仍未找到目标元素,则查找失败,返回特定的标识(如-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
与数组中最大、最小元素的关系,自适应地确定查找位置,其核心是基于线性插值的思想,假设数组元素均匀分布,通过计算得出可能包含目标元素的位置。
算法实现
- 一般实现步骤
- 确定当前查找区间的起始位置
low
和结束位置high
。 - 利用插值公式 p o s = l o w + ( k e y − a r r [ l o w ] ) × ( h i g h − l o w ) a r r [ h i g h ] − a r r [ l o w ] pos = low + \frac{(key - arr[low]) \times (high - low)}{arr[high] - arr[low]} pos=low+arr[high]−arr[low](key−arr[low])×(high−low) 计算可能的查找位置
pos
。 - 将
arr[pos]
与目标元素key
进行比较:- 如果
arr[pos]
等于key
,则查找成功,返回pos
。 - 如果
arr[pos]
小于key
,说明目标元素可能在pos
的右侧,更新low = pos + 1
,继续在新的区间内查找。 - 如果
arr[pos]
大于key
,说明目标元素可能在pos
的左侧,更新high = pos - 1
,继续在新的区间内查找。
- 如果
- 重复步骤 2 和 3,直到找到目标元素或者
low
大于high
,表示查找失败,返回特定标识(如 -1)。
- 确定当前查找区间的起始位置
- Python 代码示例
def interpolation_search(arr, key):low = 0high = len(arr) - 1while low <= high and key >= arr[low] and key <= arr[high]:if low == high:if arr[low] == key:return lowreturn -1# 计算插值位置pos = low + ((key - arr[low]) * (high - low)) // (arr[high] - arr[low])if arr[pos] == key:return poselif arr[pos] < key:low = pos + 1else:high = pos - 1return -1# 测试
arr = [10, 12, 13, 16, 18, 19, 20, 21, 22, 23, 24, 33, 35, 42, 47]
key = 18
print(interpolation_search(arr, key))
时间复杂度
- 最好情况:目标元素通过一次插值计算就被找到,时间复杂度为 O ( 1 ) O(1) O(1)。
- 最坏情况:数据分布极不均匀,插值查找退化为顺序查找,需要比较 n n n 次,时间复杂度为 O ( n ) O(n) O(n),其中 n n n 是数组中元素的个数。
- 平均情况:在数据均匀分布的情况下,平均时间复杂度为 O ( log log n ) O(\log \log n) O(loglogn),相比二分查找的 O ( log n ) O(\log n) O(logn) 效率更高。
优缺点
- 优点
- 在数据均匀分布的有序数组中,查找效率比二分查找更高,能更快地定位到目标元素。
- 基于数学原理进行位置估算,查找过程具有一定的智能性,不是简单的固定分割区间。
- 缺点
- 对数据分布要求较高,如果数据分布不均匀,插值查找的效率会大幅下降,甚至退化为顺序查找。
- 代码实现相对二分查找稍复杂,需要理解和使用插值公式。
适用场景
- 数据均匀分布的有序数组:当数组元素按照一定规律均匀排列时,如电话号码簿、字典等,插值查找可以充分发挥其优势,快速定位目标元素。
- 大规模有序数据查找:对于大规模的有序数据集合,且数据分布均匀,使用插值查找能显著提高查找效率,减少查找时间。
斐波那契查找
基本概念
斐波那契查找是一种在有序数组中进行查找的算法,它利用斐波那契数列来划分查找区间。与二分查找类似,都是用于有序数组的查找,但斐波那契查找通过斐波那契数列的特性来确定分割点,在某些场景下能减少数据的比较次数,尤其适用于对数据访问成本较高的情况。
算法实现
- 一般实现步骤
- 生成斐波那契数列,找到一个斐波那契数 F ( k ) F(k) F(k) 使得 F ( k ) − 1 F(k) - 1 F(k)−1 刚好大于或等于数组的长度 n n n。
- 初始化两个变量 f i b 2 = F ( k − 2 ) fib2 = F(k - 2) fib2=F(k−2) 和 f i b 1 = F ( k − 1 ) fib1 = F(k - 1) fib1=F(k−1),并设置一个偏移量 o f f s e t = − 1 offset = -1 offset=−1。
- 当 F ( k ) > 1 F(k) > 1 F(k)>1 时,执行以下操作:
- 计算当前比较位置 i = min ( o f f s e t + f i b 2 , n − 1 ) i = \min(offset + fib2, n - 1) i=min(offset+fib2,n−1)。
- 比较数组中第 i i i 个元素与目标元素
key
的大小:- 如果 a r r [ i ] < k e y arr[i] < key arr[i]<key,说明目标元素可能在 i i i 的右侧,更新 F ( k ) = F ( k − 1 ) F(k) = F(k - 1) F(k)=F(k−1), F ( k − 1 ) = F ( k − 2 ) F(k - 1) = F(k - 2) F(k−1)=F(k−2), F ( k − 2 ) = F ( k ) − F ( k − 1 ) F(k - 2) = F(k) - F(k - 1) F(k−2)=F(k)−F(k−1),同时更新 o f f s e t = i offset = i offset=i。
- 如果 a r r [ i ] > k e y arr[i] > key arr[i]>key,说明目标元素可能在 i i i 的左侧,更新 F ( k ) = F ( k − 2 ) F(k) = F(k - 2) F(k)=F(k−2), F ( k − 1 ) = F ( k − 1 ) − F ( k − 2 ) F(k - 1) = F(k - 1) - F(k - 2) F(k−1)=F(k−1)−F(k−2), F ( k − 2 ) = F ( k ) − F ( k − 1 ) F(k - 2) = F(k) - F(k - 1) F(k−2)=F(k)−F(k−1)。
- 如果 a r r [ i ] = k e y arr[i] = key arr[i]=key,则查找成功,返回 i i i。
- 若 F ( k ) = 1 F(k) = 1 F(k)=1 且 a r r [ o f f s e t + 1 ] = k e y arr[offset + 1] = key arr[offset+1]=key,则返回 o f f s e t + 1 offset + 1 offset+1;否则,查找失败,返回 -1。
- Python 代码示例
def fibonacci_search(arr, key):# 生成斐波那契数列fib2 = 0 # F(k - 2)fib1 = 1 # F(k - 1)fib = fib2 + fib1 # F(k)n = len(arr)while fib < n:fib2 = fib1fib1 = fibfib = fib2 + fib1offset = -1while fib > 1:i = min(offset + fib2, n - 1)if arr[i] < key:fib = fib1fib1 = fib2fib2 = fib - fib1offset = ielif arr[i] > key:fib = fib2fib1 = fib1 - fib2fib2 = fib - fib1else:return iif fib1 and arr[offset + 1] == key:return offset + 1return -1# 测试
arr = [10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100]
key = 85
print(fibonacci_search(arr, key))
时间复杂度
- 最好情况:目标元素在第一次比较时就被找到,时间复杂度为 O ( 1 ) O(1) O(1)。
- 最坏情况:需要遍历大部分元素才能找到目标元素或者确定目标元素不存在,时间复杂度为 O ( log n ) O(\log n) O(logn),与二分查找相同。
- 平均情况:平均时间复杂度也为 O ( log n ) O(\log n) O(logn),但由于其只涉及加法和减法运算,在某些硬件环境下可能比二分查找更具优势。
优缺点
- 优点
- 对硬件的适应性较好,只涉及加法和减法运算,不涉及除法运算,在一些对除法运算开销敏感的环境中效率较高。
- 在处理一些特殊的数据访问场景时,如磁盘等外存设备上的数据查找,其分割方式可以减少不必要的数据访问,提高查找效率。
- 缺点
- 需要额外的时间来生成斐波那契数列。
- 代码实现相对二分查找更复杂,理解和维护成本较高。
适用场景
- 对除法运算开销敏感的硬件环境:在一些硬件设备中,除法运算的成本较高,斐波那契查找只使用加法和减法运算,能更好地适应这类硬件环境。
- 外存数据查找:当数据存储在磁盘等外存设备上时,斐波那契查找的分割方式可以减少不必要的数据读取,提高查找效率。
哈希查找
基本原理
- 哈希函数:哈希查找的核心是哈希函数,它是一个将数据元素的键值
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 插入该位置。
删除操作
删除操作相对复杂,需要分三种情况:
- 要删除的节点是叶子节点:直接删除该节点即可。
- 要删除的节点只有一个子节点:用该子节点替换要删除的节点。
- 要删除的节点有两个子节点:找到该节点右子树中的最小节点(或左子树中的最大节点),用这个最小节点的值替换要删除节点的值,然后删除右子树中的最小节点。
二叉排序树搜索
搜索过程
在二叉排序树中搜索一个特定值的过程如下:
- 从根节点开始,将待搜索的值与根节点的值进行比较。
- 如果待搜索的值等于根节点的值,则搜索成功,返回该节点。
- 如果待搜索的值小于根节点的值,由于二叉排序树的性质,该值只可能在左子树中,因此在左子树中继续进行搜索。
- 如果待搜索的值大于根节点的值,该值只可能在右子树中,因此在右子树中继续进行搜索。
- 重复上述步骤,直到找到目标节点或者遇到空节点(表示搜索失败)。
代码实现(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)。
平衡二叉树查找过程
平衡二叉树的查找过程与普通二叉搜索树的查找过程基本一致:
- 从根节点开始,将待查找的值
target
与当前节点的值进行比较。 - 如果
target
等于当前节点的值,则查找成功,返回该节点。 - 如果
target
小于当前节点的值,则在当前节点的左子树中继续查找。 - 如果
target
大于当前节点的值,则在当前节点的右子树中继续查找。 - 重复上述步骤,直到找到目标节点或者遇到空节点(表示查找失败)。
示例代码(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}")
代码解释
- TreeNode 类:定义了 AVL 树的节点结构,包含节点的值
key
、左右子节点left
和right
以及节点的高度height
。 - AVLTree 类:
get_height
方法:用于获取节点的高度。get_balance
方法:用于计算节点的平衡因子。right_rotate
和left_rotate
方法:分别实现了右旋和左旋操作,用于调整树的平衡。insert
方法:插入新节点,并在插入后检查树的平衡情况,必要时进行旋转操作以保持树的平衡。search
方法:实现了查找功能,通过递归的方式在树中查找目标节点。
- 测试部分:创建一个 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)。
-
对于一些对查找速度要求极高的应用,如搜索引擎的缓存系统、实时数据处理系统等,平衡二叉树的高效查找性能能够满足这些场景的需求。以搜索引擎的缓存系统为例,需要快速地查找缓存中是否存在某个网页的信息,平衡二叉树可以在较短的时间内完成查找操作,提高系统的响应速度。
-
如果只需要快速查找特定的数据,而不需要数据始终保持严格的有序性,平衡二叉树可以很好地满足需求。例如,在一些游戏的物品管理系统中,需要快速查找某个物品的属性信息,平衡二叉树可以高效地实现这一功能,而不需要像排序数组那样始终保持数据的严格有序。
红黑树
定义
红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是红色或黑色。通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。红黑树必须满足以下五个性质:
- 每个节点要么是红色,要么是黑色。
- 根节点是黑色。
- 每个叶子节点(NIL节点,空节点)是黑色。
- 如果一个节点是红色的,则它的两个子节点都是黑色的。
- 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
示例
以下是一个简单的红黑树示例(为方便表示,这里用括号内的 R 表示红色节点,B 表示黑色节点):
(50B)/ \(30R) (70R)/ \ / \
(20B) (40B) (60B) (80B)
在这个红黑树中,根节点 50 是黑色,红色节点 30 和 70 的子节点都是黑色,并且从每个节点到其所有后代叶节点的简单路径上黑色节点的数量相同。
红黑树查找
查找过程
红黑树的查找过程与普通二叉搜索树的查找过程基本相同,具体步骤如下:
- 从根节点开始,将待查找的值与根节点的值进行比较。
- 如果待查找的值等于根节点的值,则查找成功,返回该节点。
- 如果待查找的值小于根节点的值,由于红黑树也是二叉搜索树,该值只可能在左子树中,因此在左子树中继续进行查找。
- 如果待查找的值大于根节点的值,该值只可能在右子树中,因此在右子树中继续进行查找。
- 重复上述步骤,直到找到目标节点或者遇到空节点(表示查找失败)。
代码实现(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 树查找过程
- 从根节点开始,将待查找的值与根节点中的键值进行比较。
- 如果待查找的值等于根节点中的某个键值,则查找成功,返回该键值所在的位置。
- 如果待查找的值小于根节点中的某个键值,则进入该键值左侧的子节点继续查找。
- 如果待查找的值大于根节点中的所有键值,则进入最右侧的子节点继续查找。
- 重复上述步骤,在子节点中继续比较和查找,直到找到目标键值或者到达叶子节点。如果到达叶子节点仍未找到目标键值,则查找失败。
代码实现(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(log⌈m/2⌉n),其中 m m m 是 B 树的阶数。因此,B 树查找操作的时间复杂度为 O ( log ⌈ m / 2 ⌉ n ) O(\log_{\lceil m/2 \rceil} n) O(log⌈m/2⌉n),在实际应用中,由于 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(log⌈m/2⌉n)。对于范围查找,由于叶子节点之间有指针相连,时间复杂度为 O ( k + log ⌈ m / 2 ⌉ n ) O(k + \log_{\lceil m/2 \rceil} n) O(k+log⌈m/2⌉n),其中 k k k 是范围内键值的数量。
- 空间复杂度:同样为 O ( n ) O(n) O(n),主要用于存储树中的节点。
应用场景
B + 树在数据库系统中应用广泛,如 MySQL 的 InnoDB 存储引擎默认使用 B + 树作为索引结构。因为 B + 树的结构非常适合范围查询,并且由于所有数据都存储在叶子节点,使得数据库的插入、删除和查找操作更加高效和稳定。同时,叶子节点的有序链表结构也方便进行顺序访问,提高了数据的读取效率。
分块查找
也称为索引顺序查找,它是一种介于顺序查找和二分查找之间的查找方法。以下从基本思想、实现步骤、复杂度分析、优缺点和适用场景等方面详细介绍:
基本思想
分块查找将一个线性表分成若干个块,每个块内的元素可以是无序的,但块与块之间是有序的,即后一个块中所有元素的值都大于前一个块中所有元素的值。同时,还需要建立一个索引表,索引表中记录了每个块的最大关键字以及该块在原线性表中的起始位置,索引表是按关键字有序排列的。
实现步骤
分块查找主要分为两步:
- 确定待查元素所在的块:使用二分查找或顺序查找在索引表中查找,根据索引表中记录的块的最大关键字,确定待查元素可能存在于哪个块中。
- 在块内查找元素:在确定的块中使用顺序查找的方法查找待查元素。
示例及代码实现
假设我们有一个线性表 [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+树查找、分块查找)
常用的查找算法: 顺序查找:最简单的查找算法,适用于无序或数据量小的情况,逐个元素比较查找目标值。二分查找:要求数据有序,通过不断比较中间元素与目标值,将查找范围缩小一半,效率…...
2526考研资料分享 百度网盘
通过网盘分享的文件:01、2026【考研数学】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492mP3w?pwd98wg 提取码:98wg--来自百度网盘超级会员v3的分享 通过网盘分享的文件:01、2026【考研政治】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492…...

网络编程(24)——实现带参数的http-get请求
文章目录 二十四、day241. char 转为16进制2. 16进制转为 char3. URL 编码函数4. URL 解码函数5. 实现 get 请求参数的解析6. 测试 二十四、day24 我们在前文通过beast实现了http服务器的简单搭建,但是有很多问题我们并没有解决。 在前文中,我们的 get…...

东方财富股吧发帖与评论爬虫
东方财富股吧发帖与评论爬虫 东方财富股吧爬虫 写在开头项目介绍主要功能文件介绍爬取逻辑 a. 爬取帖子信息b. 爬取评论信息 使用步骤 1. 下载代码2. MongoDB 安装3. Webdriver 安装4. 运行 main.py5. 查看数据 踩过的坑附录(运行结果) 东方财富股吧爬…...
【Elasticsearch】match_bool_prefix查询
match_bool_prefix查询是 Elasticsearch 中一种用于全文搜索的查询方式,适用于需要同时匹配多个词汇,但词汇顺序不固定的情况,它结合了布尔查询(bool)和前缀查询(prefix)的功能,适用…...

微信小程序image组件mode属性详解
今天学习微信小程序开发的image组件,mode属性的属性值不少,一开始有点整不明白。后来从网上下载了一张图片,把每个属性都试验了一番,总算明白了。现总结归纳如下: 1.使用scaleToFill。这是mode的默认值,sc…...
数据结构:最小生成树
1.基本概念 生成树:连通无向图的生成树是包含图中所有顶点的极小连通子图(无环)。 最小生成树:所有生成树中边权重总和最小的那棵。 2.常用算法 克鲁斯卡尔算法(Kruskal) 步骤: 将所有边按权…...

C语言-章节 4:函数的定义与声明 ——「神秘法术的卷轴」
少年和 Inta 成功通过运算符与表达式的考验后,继续在函数城堡中探索。他们沿着一条闪烁着幽光的走廊前行,走廊两侧的墙壁上刻满了奇异的符号,仿佛在诉说着古老的编程秘密。终于,他们来到了一间神秘的房间,房间中央悬浮…...

《云原生安全攻防》-- K8s镜像安全:镜像全生命周期安全管理
从攻击者的角度来看,针对容器镜像的软件供应链攻击和镜像投毒等攻击方式,不仅攻击成本低,而且还能带来更高且持久的收益。因此,镜像安全问题变得日益突出。 在本节课程中,我们将深入探讨镜像全生命周期的安全管理&…...

uniapp商城之首页模块
文章目录 前言一、自定义导航栏1.静态结构2.修改页面配置3.组件安全区适配二、通用轮播组件1. 静态结构组件2.自动导入全局组件3.首页轮播图数据获取三、首页分类1.静态结构2.首页获取分类数据并渲染四、热门推荐1.静态结构2.首页获取推荐数据并渲染3.首页跳转详细推荐页五、猜…...
【Javascript Day13、14、15、16】
html的DOM操作 // JS 是为了让页面实现动态网页效果 // 动态和静态区分取决于JS的和页面标签的数据交互 // 动态网页:有数据交互 // 静态网页:无数据交互 // JS 和 元素的关联操作对象 DOM // 整个HT…...
linux 板子的wifi模块连上路由器后,用udhcpc给板子wifi分配ip,udhcpc获取到ip,但没有写入wlan0网卡上
linux 板子的wifi模块连上路由器后,用udhcpc给板子wifi分配ip,udhcpc获取到ip,但没有写入wlan0网卡上 这里的问题是 /usr/share/udhcpc/default.script脚本有问题 用下面正确脚本,即可写进去 #!/bin/sh# udhcpc script for busybox # Copyr…...

openGauss 3.0 数据库在线实训课程13: 学习逻辑结构:表管理1
前提 我正在参加21天养成好习惯| 第二届openGauss每日一练活动 课程详见:openGauss 3.0.0数据库在线实训课程 学习目标 学习openGauss表的创建、搜索路径和访问方法等 课程作业 1.创建一个表(默认,不指定模式),查…...

网络编程-
文章目录 网络编程套接字UDP/TCP的api使用 网络编程套接字 socket,是操作系统给应用程序(传输层给应用层)提供的api,Java也对这个api进行了封装。 socket提供了两组不同的api,UDP有一套,TCP有一套&#x…...
基于单片机的常规肺活量SVC简单计算
常规肺活量 SVC(Slow Vital Capacity)是指尽力吸气后缓慢而又完全呼出的最大气量。 成年男性的肺活量通常在 3500-4000ml 之间,成年女性的肺活量通常在 2500-3000ml 之间。 单片机一般通过外接流量传感器,使用ADC高速采集的方式…...

【PostgreSQL】PG在windows下的安装
一、准备 通过官网下载安装文件,官方下载路径如下: https://www.postgresql.org/download/windows/ 二、安装 双击postgresql-17.3-1-windows-x64.exe文件,启动安装,进入安装步骤,点击Next 选择PG安装路径ÿ…...

电动汽车电池监测平台系统设计(论文+源码+图纸)
1总体设计 本次基于单片机的电池监测平台系统设计,其整个系统架构如图2.1所示,其采用STC89C52单片机作为控制器,结合ACS712电流传感器、TLC1543模数转换器、LCD液晶、DS18B20温度传感器构成整个系统,在功能上可以实现电压、电流、…...

基于和声搜索(Harmony Search, HS)的多中心点选址优化算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于和声搜索(Harmony Search, HS)的多中心点选址优化算法matlab仿真。可以设置多个不同的中心点。 2.测试软件版本以及运行结果展示 matlab2022a/matlab2024b版…...

单链表的概念,结构和优缺点
1. 概念 链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 2. 单链表的结构 单链表是由一系列节点组成的线性结构,每个结点包含两个域。:数据域和指针域。 数据域用来…...

SpringBoot+数据可视化的奶茶点单购物平台(程序+论文+讲解+安装+调试+售后)
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统介绍 本奶茶点单购物平台搭建在 Spring Boot 框架之上,充分利用其强大的依赖管理机…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...