【数据结构】七、查找:1.查找的概念、线性结构查找(顺序、折半(二分)、插值、稠密、分块、倒排)

news2025/7/10 14:37:03

一、查找Search

在这里插入图片描述

文章目录

  • 一、查找Search
    • 1.查找的基本概念
      • 1.1基本概念
      • 1.2算法评价标准
  • 二、线性结构
    • 1.顺序表查找
      • ❗1.1顺序查找
        • 1.1.1算法思想
        • 1.1.2顺序查找效率分析
    • 2.有序表查找
      • ❗2.1折半查找
        • 2.1.1算法思想
        • 2.1.2判定树构造
        • 2.1.3通过判定树进行查找效率分析
        • 2.1.4被查找概率不相等(优化)
      • 2.2插值查找(折半优化)
      • 2.3斐波那契查找
    • 3.线性索引查找
      • 3.1稠密索引
      • ❗3.2分块索引
        • 3.2.1算法思想
        • 3.2.2查找效率分析
        • 3.2.3分块索引的优化
      • 3.3倒排索引

1.查找的基本概念

1.1基本概念

查找(Searching):就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素( 或记录)。

查找表(Search Table):是由同一类型的数据元素(或记录)构成的集合。
可以是线性结构、树形结构、图状结构…

关键字(Key):数据元素中唯一标识该元素的某个数据项的值,使用基于关键字的查找,查找结果应该是唯一的。

例如,在由一个学生元素构成的数据集合中,学生元素中“学号”这一数据项的值唯一地标识一名学生。

静态查找表(Static Search Table):只作查找操作的查找表(只查不改)。主要操作:

  1. 查询某个“特定的”数据元素是否在查找表中
  2. 检索某个“特定的”数据元素和各种属性

动态查找表(Dynamic Search Table): 在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素(边查边改)。主要操作:

  1. 查找时插入不存在的数据元素。
  2. 查找时删除已存在的数据元素。

1.2算法评价标准

查找长度:在查找运算中,一次查找需要对比关键字的次数称为查找长度。

平均查找长度(ASL, Average Search Length.):所有查找过程中进行关键字的比较次数的平均值。

平均查找长度是衡量查找算法效率的最主要的指标。

其数学定义为:
A S L = ∑ i = 1 n P i C i ASL=\sum ^n_{i=1} P_iC_i ASL=i=1nPiCi

  • n:数据元素个数
  • Pi:查找第 i 个元素的概率,一般认为每个数据元素的查找概率相等,即Pi= 1/n
  • Ci:查找第 i 个元素的查找长度

例如:

在这里插入图片描述

在这里插入图片描述

二、线性结构

1.顺序表查找

❗1.1顺序查找

顺序查找(Sequential Search) 又叫线性查找,是最基本的查找技术。通常用于线性表。

1.1.1算法思想

算法思想(严谨):从线性表的一端开始,逐个检查关键字是否满足给定的条件。若查找到某个元素的关键字满足给定条件,则查找成功,返回该元素在线性表中的位置;若已经查找到表的另一端,但还没有查找到符合给定条件的元素,则返回查找失败的信息。

算法思想(个人):从头到尾挨个找(或者反过来也OK)

有哨兵顺序查找:倒序查找,在下标为0处(查找尽头)设置为关键字,称之为哨兵。返回其他值为查找成功,返回0表示失败。

在这里插入图片描述

//有哨兵顺序查找
int Sequential_Search(int *a, int n, int key){
	int i;
	a[0] = key;	//设置a[0]为关键字,称之为“哨兵”
	i = n;	//循环从数组尾部开始
	while(a[i] != key){
		i--;
	}
	return i;	//返回0则说明查找失败
}

这种在查找方向的尽头放置“哨兵”免去了在查找过程中每一次比较后都要判断查找位置是否越界的小技巧,看似与原先差别不大,但在总数据较多时,效率提高很大,是非常好的编码技巧。

上述顺序表查找时间复杂度是O(n)

1.1.2顺序查找效率分析

倒序查找,如果第一个就是查找目标,那么只需要对比关键字1次,如果是倒数第2个,那么就对比2次。如果查找失败,那么就直接遍历到0号元素。

所以:
成功 A S L = ∑ i = 1 n P i C i = 1 n ∗ ∑ i = 1 n C i = 1 n ∗ ( 1 + 2 + 3 + . . . + n ) = n + 1 2 失败 A S L = n + 1 \begin{equation}\begin{split} 成功ASL &= \sum ^n_{i=1} P_iC_i \\ &= \frac 1n * \sum ^n_{i=1}C_i \\ &= \frac 1n *(1+2+3+...+n) \\ &= \frac {n+1}2 \\ 失败ASL = n+1 \end{split}\end{equation} 成功ASL失败ASL=n+1=i=1nPiCi=n1i=1nCi=n1(1+2+3+...+n)=2n+1

2.有序表查找

如果一个表是从小到大(升序)或者从大到小(降序),那么查找效率可以提高很多。

❗2.1折半查找

折半查找(Binary Search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储。

2.1.1算法思想

算法思想(严谨):在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所有查找区域无记录,查找失败为止。

算法思想(个人):因为顺序表有顺序,那么直接从中间开始查找,把整个表一分为二,如果关键字比中间的值更大,那么就往更大的一半查找。依然从中间开始查找对比大小。

// 从小到大,升序
int Binary_Search(SeqList L, ElemType key){
	int low=0;	//头
    int high = L.length - 1;	//尾
    int mid;
    
	while(low <= high){
		mid = (low + high)/2;	//取中间位置
		if(L.elem[mid] == key){
			return mid;	//查找成功返回所在位置
		}else if(L.elem[mid] > key){
			high = mid - 1;	//从前半部分继续查找
		}else{
			low = mid + 1;	//从后半部分继续查找
		}
	}
	return -1;	//查找失败,返回-1
}

查找判定树:折半查找的过程可用二叉树来描述,称为判定树。折半查找的判定树一定是平衡二叉树只有最下面一层是不满的)。

我们知道,具有n个结点的二叉树的深度(树高)为 ⌈ l o g 2 ( n + 1 ) ⌉ 或者 ⌊ l o g 2 n ⌋ + 1 \lceil log_2(n+1) \rceil或者\lfloor log_2n \rfloor +1 log2(n+1)⌉或者log2n+1,那么 A S L = ⌈ l o g 2 ( n + 1 ) ⌉ ASL=\lceil log_2(n+1) \rceil ASL=log2(n+1)⌉

所以,折半查找的时间复杂度为O(log2n)

平均情况下(但是不是所有情况),比顺序查找的效率高。

因为折半查找需要方便地定位查找区域,所以它要求线性表必须具有随机存取的特性。因此,该查找法仅适合于顺序存储结构不适合于链式存储结构,且要求元素按关键字有序排列。

2.1.2判定树构造

因为折半查找是删去中间的元素,然后进行两边平分的,那么就需要关注整体的元素的个数是奇数还是偶数。

如果是奇数个元素(11):

在这里插入图片描述

如果是偶数个元素(10):

在这里插入图片描述

总结:

  • 奇数个元素,则mid分隔后,左右两部分元素个数相等。
  • 偶数个元素,则mid分隔后,左半部分比右半部分少一个元素(右边多,因为计算机是向下取整)。

折半查找的判定树中,若 m i d = ⌊ ( l o w + h i g h ) / 2 ⌋ + 1 mid=\lfloor (low+high)/2 \rfloor +1 mid=⌊(low+high)/2+1,则对于任何一个结点,必有:
右子树结点数 − 左子树结点数 = 0 或 1 右子树结点数-左子树结点数=0或1 右子树结点数左子树结点数=01
也即是左右子树的深度之差不会超过 1。那么折半查找的判定树一定是平衡二叉树

2.1.3通过判定树进行查找效率分析

在这里插入图片描述

失败节点的个数是n+1,也就是成功结点的空链域的数量。

在这里插入图片描述

在这里插入图片描述

一个成功结点的查找长度C = 自身所在的层数。

一个失败结点的查找长度C = 父结点所在的层数。

默认情况下,各种失败情况或成功情况都等概率发生。

2.1.4被查找概率不相等(优化)

被查找概率不相等时候,那么可以把查找概率大的元素放在前面,先进行查找,这样可以降低查找成功的ASL

不足:但是这样就打破了排序,那么查找失败的ASL就需要全部遍历到哨兵才可以。

2.2插值查找(折半优化)

现在我们的新问题是,为什么一定要折半,而不是折四分之一或者折更多呢?比如要在取值范围0 ~ 10000之间100个元素从小到大均匀分布的数组中查找5,我们自然会考虑从数组下标较小的开始查找。所以,折半查找还是有改善空间的。

对上述折半查找的mid值获取等式变换后可得到:

mid = (low + high)/2 = low + (high - low)/2;

也就是mid等于最低下标low加上最高下标high与low的差的一半。

大佬们考虑的就是将这个1/2进行改进,改进为下面的计算方案:

mid = low + (key-L.elem[low]) / ( (L.elem[high] - L.elem[low]) * (high-low) );	//插值

就得到了另一种有序表查找算法,插值查找法

**插值查找(Interpolation Search)**是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式。

从时间复杂度来看,它也是O(log2 n),但对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好得多。

反之,数组中如果分布类似0,1,2,2000,2001,…999998,99999这种极端不均匀的数据,用插值查找未必是很合适的选择。

2.3斐波那契查找

斐波那契查找(Fibonacci Search),它是利用了黄金分割原理来实现的。

斐波那契数列(Fibonacci sequence),又称黄金分割数列,以兔子繁殖为例子而引入,故又称“兔子数列”。其数值为:1、1、2、3、5、8、13、21、34……在数学上,这一数列以如下递推的方法定义:

F(0)=0,
F(1)=1,
F(n)=F(n-1) + F(n-2)
    //(n ≥ 2, n ∈ N)
//F(n) = 前两数之和

这里定义一个斐波那契数列:

下标012345678910
F0112358132134

斐波那契查找算法的核心在于:

  1. 当key = a[mid]时,查找就成功;
  2. 当key < a[mid]时,新范围是第low个到第mid-1个,此时范围个数为F[k-1]-1个;
  3. 当key > a[mid]时,新范围是第m+1个到第high个,此时范围个数为F[k-2]-1个。

在这里插入图片描述

也就是说,如果要查找的记录在右侧,则左侧的数据都不用再判断了,不断反复进行下去,对处于当中的大部分数据,其工作效率要高一些,而且斐波那契查找只是最简单加减法运算,所以尽管斐波那契查找的时间复杂也为O(logn),但就平均性能来说,斐波那契查找要优于折半查找。

不过如果是最坏情况,比如这里key=1,那么始终都处于左侧长半区在查找,则查找效率要低于折半查找。

算法如下:

//斐波那契查找
int Fibonacci_Search(int *a, int n, int key){
	int low, high, mid, i, k;
	low = 0;	//定义最低下标为记录首位
	high = n;	//定义最高下标为记录末尾
	k = 0;
	while(n > F[k] - 1){
		//计算n位于斐波那契数列的位置
		k++;
	}
	for(i=n; i<F[k]; i++){
		//在尾部补上F[k]-n-1个数,大小等于尾部最大值,否则会存在数组溢出
		a[i]=a[n];
	}
	while(low <= hight){
		mid = low + F[k-1]-1;	//计算当前分隔的下标
		if(key < a[mid]){
			//若查找记录小于当前分隔记录
			hight = mid - 1;	//最高下标调整到分隔下标mid-1处
			k = k - 1;	//斐波那契数列下标减一位
		}else if(key > a[mid]){
			//若查找记录大于当前分隔记录
			low = mid + 1;	//最低下标调整到分隔下标mid+1处
			k = k - 2;	//斐波那契数列下标减两位
		}else{
			if(mid <= n){
				return mid;	//若相等则说明mid即为查找的位置
			}else{
				return n;	//若mid>n说明是补全数值,返回n
			}
		}
	}
	return -1;
}

3.线性索引查找

现实生活中计算机要处理的数据量是极其庞大的,而数据结构的最终目的是提高数据的处理速度,索引是为了加快查找速度而设计的一种数据结构。

索引就是把一个关键字与它对应的记录相关联的过程, 一个索引由若干个索引项构成,每个索引项至少应包含关键字和其对应的记录在存储器中的位置等信息。索引技术是组织大型数据库以及磁盘文件的一种重要技术。

  • 索引
    • 索引项
      • 关键字
      • 关键字对应的记录在存储器的位置

索引按照结构可以分为:

  1. 线性索引
    1. 稠密索引
    2. 分块索引
    3. 倒排索引
  2. 树形索引
  3. 多级索引

这里主要介绍线性索引,所谓线性索引就是将索引项集合组织为线性结构,也称为索引表。我们重点介绍三种线性索引:稠密索引、分块索引和倒排索引。

3.1稠密索引

稠密索引是很简单直白的一种索引结构。

稠密索引是指在线性索引中,将数据集中的每个记录对应一个索引项,而索引项一定是按照关键码有序的排列。如下图所示:

在这里插入图片描述

索引项有序也就意味着,我们要查找关键字时,可以用到折半、插值、斐波那契等有序查找算法,提高了效率。这是稠密索引优点,但是如果数据集非常大,比如上亿,那也就意味着索引也得同样的数据集长度规模,对于内存有限的计算机来说,可能就需要反复去访问磁盘,查找性能反而大大下降了。

❗3.2分块索引

稠密索引因为索引项与数据集的记录个数相同,所以空间代价很大。为了减少索引项的个数,我们可以对数据集进行分块,使其分块有序,然后再对每一块建立一个索引项,从而减少索引项的个数。

分块有序,又称索引顺序查找。是把数据集的记录分成了若千块,并且这些块需要满足两个条件:

  1. 块内无序:即每一块内的记录不要求有序。
  2. 块间有序:例如,要求第二块所有记录的关键字均要大于第一块中所有记录的关键字,第三块的所有记录的关键字均要大于第二块的所有记录关键字…因为只有块间有序,才有可能在查找时带来效率。

在这里插入图片描述

对于分块有序的数据集,将每块对应一个索引项, 这种索引方法叫做分块索引。我们定义的分块索引的索引项结构分三个数据项:

  • 最大关键码:它存储每一块中的最大关键字,这样的好处就是可以使得在它之后的下一块中的最小关键字也能比这一块最大的关键字要大。
  • 块长:存储了块中的记录个数,以便于循环时使用。
  • 块首指针:用于指向块首数据元素的指针,便于开始对这一块中记录进行遍历。
3.2.1算法思想
  1. 在索引表中确定待查记录所属的分块(可顺序、可折半);
  2. 在块内顺序查找(全部遍历)。
//索引表
typedef struct {
	ElemType maxValue;
    int low,high;
}Index;
//顺序表存储实际元素
ElemType List [100] ;

【易错点】对索引表进行折半查找时,若索引表中不包含目标关键字,则折半查找最终停在low>high,要在low所指分块中查找。

3.2.2查找效率分析

如上图,有0-13共14个元素,它们各自被查找的概率都是1/14。

假设,长度为 n 的查找表被均匀地分为 b 块,每块 s 个元素,那么可以推断n=sb

索引查找块内查找的平均查找长度分别为LI、LS,则分块查找的平均查找长度为:
A S L = L I + L s ASL = L_I + L_s\\ ASL=LI+Ls

  1. 如果用顺序查找来查找索引

L I = 1 + 2 + . . . + b b = b + 1 2 L S = 1 + 2 + . . . + s s = s + 1 2 所以 : A S L = b + 1 2 + s + 1 2 并且 : n = s b 那么 : A S L = s 2 + 2 s + n 2 s = 1 2 s + 1 + n 2 s 当 s = n 时 , A S L m i n = n + 1 L_I = \frac {1+2+...+b}b = \frac {b+1}2 \\ L_S = \frac {1+2+...+s}s = \frac {s+1}2 \\ \\ 所以:ASL = \frac{b+1}2 + \frac{s+1}2 \\ 并且:n=sb \\ 那么:ASL = \frac{s^2+2s+n}{2s} = \frac 12s+1+\frac n{2s}\\ \\ 当s=\sqrt n时,ASL_{min}=\sqrt n +1 LI=b1+2+...+b=2b+1LS=s1+2+...+s=2s+1所以:ASL=2b+1+2s+1并且:n=sb那么:ASL=2ss2+2s+n=21s+1+2sns=n ,ASLmin=n +1

也就是,当把元素分为 n \sqrt n n 块,每块有 n \sqrt n n 个元素的时候,ASL最小。

eg: 若元素有n=10000个,求最小ASL。

10000 = 100 \sqrt {10000}=100 10000 =100 ,那么最小 ASL=100+1 = 101

  1. 如果用折半查找来查找索引

L I = ⌈ l o g 2 ( b + 1 ) ⌉ L S = 1 + 2 + . . . + s s = s + 1 2 所以 : A S L = ⌈ l o g 2 ( b + 1 ) ⌉ + s + 1 2 L_I = \lceil log_2(b+1) \rceil \\ L_S = \frac {1+2+...+s}s = \frac {s+1}2 \\ \\ 所以:ASL = \lceil log_2(b+1)\rceil + \frac{s+1}2 \\ LI=log2(b+1)⌉LS=s1+2+...+s=2s+1所以:ASL=log2(b+1)⌉+2s+1

3.2.3分块索引的优化

若查找表是“动态查找表”,那么因为要删除和添加新的元素,那么就需要把整个表的下标都进行前移或后移。所以使用链式存储的方式:

在这里插入图片描述

3.3倒排索引

搜索引擎中涉及很多搜索技术,这里介绍一种最简单,也是最基础的搜索技术:倒排索引

倒排索引(inverted index):其中记录号表存储具有相同次关键字的所有记录的记录号(可以是指向记录的指针或者是该记录的主关键字)。这样的索引方法就是倒排索引。

我们举个简单的例子:

假如下面两篇极短的文章。

  1. Books and friends should be few but good.
  2. A good book is a good friend.

忽略字母大小写,我们统计出每个单词出现在哪篇文章之中:文章1、文章2、文章(1,2),得到下面这个表,并对单词做了排序:

英文单词(次关键码)文章编号(记录号表)
a2
and1
be1
book1,2
but1
few1
friend1,2
good1,2
is2
should1

有了这样一张单词表,我们要搜索文章,就非常方便了。如果你在搜索框中填写“book"关键字。系统就先在这张单词表中有序查找“book" ,找到后将它对应的文章编号1和2的文章地址返回。

在这里这张单词表就是索引表,索引项的通用结构是:

  • 次关键码,例如上面的“英文单词”;
  • 记录号表,例如上面的“文章编号"。

这名字为什么要叫做“倒排索引”呢?

顾名思义,倒排索引源于实际应用中需要根据属性(或字段、次关键码)的值来查找记录(或主关键编码)。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引。

当然,现实中的搜索技术是非常复杂的,要考虑诸多因素用到诸多技术,由于本文的侧重点并非搜索引擎,所以于此不再赘述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2040895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ReactNative笔记(自用)

环境 ios更换gem镜像源&#xff1a; 查看当前源: gem sources -l 移除默认源: gem sources --remove https://rubygems.org/。添加新的源: 添加 Ruby China 的镜像源&#xff1a; gem source -a https://gems.ruby-china.com/或者添加其他镜像源。 清华大学的gem源: htt…

进阶-1.存储引擎

存储引擎 存储引擎1.MySQL体系结构2.存储引擎简介3.存储引擎特点3.1 InnoDB3.2 MyISAM3.3 Memory 4. 存储引擎选择 存储引擎 1.MySQL体系结构 2.存储引擎简介 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现。存储引擎是基于表的&#xff0c;而不是基于库的&…

【数学分析笔记】第2章第1节实数系的连续性(1)

2. 数列极限 2.1 实数系的连续性 人类对数系认识的历史&#xff1a; 人类最早对数系的认识是自然数集合 N \mathbb{N} N&#xff0c;自然数系对加法和乘法是封闭的&#xff08;这里的封闭是指&#xff1a;若 m ∈ N , n ∈ N ⇒ m n ∈ N , m n ∈ N m\in\mathbb{N},n\in\ma…

芯片用什么胶粘接牢固?​​​​​​​

芯片用什么胶粘接牢固?芯片粘接胶的牢固性对于电子产品的性能和可靠性至关重要。选择合适的胶水可以确保芯片能够稳定、可靠地固定在基板上。芯片的粘接通常涉及几种不同类型的胶水&#xff0c;每种胶水都有其特定的应用场景和性能特点。以下是几种常见的用于芯片粘接的胶水类…

C Primer Plus第十二章编程练习

第十二章编程练习 第一题要求我们不使用全局变量&#xff0c;修改程序12.4&#xff0c;那我们就用指针作为参数去传递变量的地址&#xff0c;去修改变量的值&#xff0c;完整程序代码以及运行结果如下&#xff1a; #include<stdio.h> //int units 0; void critic(int …

node卸载与安装

1.直接使用卸载程序卸载 2.安装新的Node 官网下载并执行下一步直到完成 3.Idea配置不同版本的node file->settings->Languages & Frameworks->Node.js and NPM->增加带选项->选择指定版本

ubuntu下使用docker、socket、yolov5进行图像处理数据交互记录

ubuntu下使用docker、socket、yolov5进行图像处理数据交互记录 概述&#xff1a;主要实现了在宿主机上通过8000端口传递一张图像给docker镜像&#xff0c;然后镜像中处理后&#xff0c;通过8001端口回传处理后的图像给宿主机。 第一章、构建镜像 一、dockerfile文件 1.拉取…

jQuery:配置与选择器

一&#xff0c;jQuery的配置 jQuery下载 这里以compressed为例&#xff0c;根据喜好也可以选择uncompressed版本。 进入jQuery代码中&#xff0c;右键另存为&#xff0c;保存到自己项目中&#xff1a; 导入jQuery <!DOCTYPE html> <html lang"en"><…

WO Mic 手机变身免费麦克风

目录 一、主要特点 1.支持多种连接方式 2.应用广泛 3.低延迟 4.简易配置 5.自动连接 6.音频格式 二、软件下载 三、软件安装 四、系统连接 五、测试 直播的时候,上课的时候,会议的时候……突然发现没有麦克风或者电脑麦克风有故障,这可怎么办呢?今天给大家介绍一…

ONNX深入研究(1):AI模型优化与加速方法

得益于现有的硬件和加速器&#xff0c;深度学习在 2010 年代初开始兴起&#xff0c;在这种支持下&#xff0c;研究人员和工程师提出了更复杂、更大的模型。然而&#xff0c;内存消耗和执行时间等限制仍然是一个挑战。由于计算资源的限制&#xff0c;这些挑战在工程和商业领域变…

UE5学习笔记11-为拿取武器添加动画

一、一点说明 动画实例通过扩展为所有机器上的每个字符都存在动画蓝图&#xff0c;动画实例只能访问该计算机上的变量。 二、思路 我在武器组件中有一个武器类的指针&#xff0c;判断当前指针是否为空去判断当前角色是否装备武器 三、实现 1.在角色C类中添加是否装备武器的函…

OpenCV--图片操作

一.图片旋转 图片旋转是图像处理中的一种基本操作&#xff0c;用于将图像按照指定的角度进行旋转。旋转操作在图像编辑、计算机视觉和图形学等领域中非常常见&#xff0c;通常用来调整图像的方向或在图像识别中进行数据增强。 旋转的基本原理 图片旋转涉及到将每个像素从原始…

(贪心) LeetCode 376. 摆动序列

原题链接 一. 题目描述 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。 例如&#xff0c; [1, 7, 4, 9, 2,…

电脑技巧:电脑系统盘文件清理指南

目录 一、可以安全删除的文件 1.1. 临时文件 1.2. 系统缓存文件 1.3. 回收站 1.4. 安装包缓存 1.5. 系统还原点 1.6. 已下载的更新文件 1.7. 浏览器缓存 1.8. Thumbs.db 文件 1.9. Windows日志文件 1.10. Windows.old 文件夹 二、系统文件清理注意点 三、系统文件…

推荐一款Python开源移动应用安全测试分析工具!!!

今天给大家推荐一个安全测试相关的开源项目&#xff1a;nccgroup/house 1、介绍 它是一个由 NCC Group 开发的&#xff0c;一个基于Frida和Python编写的动态运行时移动应用分析工具包&#xff0c;提供了基于 Frida 的 Web GUI 界面&#xff0c;旨在简化动态函数挂钩的过程&am…

Linux---04---Vim编辑器

一、vi/vim编辑器介绍 vi 是 visual interface 的简称&#xff0c;是Linux系统提供的一个文本编辑工具&#xff0c;可以对文件内容进行编辑&#xff0c;类似于Windows中的记事本。 vim 是 vi 的加强版本&#xff0c;兼容 vi 的所有指令&#xff0c;不仅能编辑文本&#xff0c…

Using locally deployed llm with langchain‘s openai llm wrapper

题意&#xff1a;使用本地部署的LLM与Langchain的OpenAI LLM封装器 问题背景&#xff1a; I have deployed llm model locally which follows openai api schema. As its endpoint follows openai schema, I dont want to write separate inference client. 我已经本地部署了…

Mybatis框架介绍

Mybatis入门 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Jav…

IT管控体系建设(集团企业),附网传埃森哲案例

&#xff08;一&#xff09;集团IT企业IT管控组织结构设计 1.集团分管领导 职能&#xff1a;最高级别的管理&#xff0c;负责对整个集团的信息化管控进行监督和决策。 2.CIO/管理部主任 职能&#xff1a;负责整体的IT战略和方向&#xff0c;直接向集团分管领导汇报。负责协…

一分钟了解:Java 冒泡排序算法

1. 冒泡排序算法介绍 冒泡排序是最简单的排序算法&#xff0c;如果相邻元素的顺序错误&#xff0c;则通过反复交换相邻元素来工作。Java 中的冒泡排序不是对数组进行排序的最佳方法&#xff0c;但却是最基本的实现之一。在本文中&#xff0c;我们将学习如何用 Java 编写冒泡排…