算法----BF算法KMP算法

请想象一个情景:

当你脑海中突然浮现出一个词,你该怎么去找到这个词的有关内容?

打开我们浏览器的搜索框,输入你想的这个词,然后点击Enter。浏览器就会自动搜索与该词匹配的内容。

这个过程实际上可以简化成以下形式:

有一个文本串S,一个模式串P(也叫子串),现在要查找PS中的位置。

我们今天所讨论的两个算法就是有关该过程的算法。

事实上,对于检索,无非就是两个字符串的匹配过程,模式串是你想要匹配的串,主串是你搜索所在串。

针对模式串中的一个个字符与主串进行匹配,

匹配成功则继续往后匹配;

匹配失败则跳过该串段继续匹配,直到主串中出现与模式串完全相同的串段,此时则成功找到。

所以检索无非就是模式匹配的过程。

BF算法和KMP算法是较为著名的模式匹配算法,接下来作出详细介绍。

BF算法

BF算法(Brute-Force)也称为暴力算法,其核心原理是逐个比较文本串和模式串的字符,如果匹配失败,则通过向右移动模式串的位置,再次进行比较。

算法步骤

我们设主串和模式串中的字符位置分别为ij

  • 如果当前字符匹配成功(即T[i] == P[j]),则i++,j++,继续匹配下一个字符;
  • 如果当前字符匹配失配(即T[i]! = P[j]),则令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0

举例:

假设我们有一个文本串T为:“ABCDABCDABCE”,以及一个模式串P为:“ABCE”,我们要在文本串T中查找是否存在模式串P。

首先,我们将文本串T和模式串P在一条直线上对齐:

文本串T:  ABCDABCDABCE
模式串P:  ABCE

然后,我们从文本串T的第一个字符开始和模式串P的第一个字符比较:

第一次比较:'A’和’A’相等。

文本串T:  ABCDABCDABCE
模式串P:  A

第二次比较:'B’和’B’相等。

文本串T:  ABCDABCDABCE
模式串P:  AB

第三次比较:'C’和’C’相等。

文本串T:  ABCDABCDABCE
模式串P:  ABC

第四次比较:'D’和’E’不相等,出现失配。

文本串T:  ABCDABCDABCE
模式串P:  ABCE

在匹配失败后,我们将模式串P向右移动一位,重新从文本串T的当前位置和模式串P的第一个字符开始比较:

文本串T:  ABCDABCDABCE
模式串P:   A

第一次比较:'A’和’B’不相等。出现失配。

那么再将模式串P向右移动一位,重新从文本串T的当前位置和模式串P的第一个字符开始比较:

文本串T:  ABCDABCDABCE
模式串P:    A

第一次比较:'A’和’C’不相等。出现失配。

继续类似的比较过程,直到文本串T遍历完毕。

代码演示

根据上述过程我们可以写出BF算法的代码:

int ViolentMatch(char* s, char* p)
{
	int sLen = strlen(t);
	int pLen = strlen(p);
 
	int i = 0;
	int j = 0;
	while (i < sLen && j < pLen)
	{
		if (t[i] == p[j])
		{
			//①如果当前字符匹配成功(即T[i] == P[j]),则i++,j++    
			i++;
			j++;
		}
		else
		{
			//②如果失配(即T[i]! = P[j]),令i = i - (j - 1),j = 0    
			i = i - j + 1;
			j = 0;
		}
	}
	//匹配成功,返回模式串p在文本串s中的位置,否则返回-1
	if (j == pLen)
		return i - j;
	else
		return -1;
}

我们发现这种确实可以被称作暴力解法:无论后面的元素是否匹配,模式串P都会回溯到它的第一个字符开始重新比较,而例如在第二次重新匹配的过程中,实际上是必定失配的,从而又要继续回溯再重新比较,属实暴力且死板。

时间复杂度

BF算法的时间复杂度取决于文本串T的长度为n,模式串P的长度为m。在最坏情况下,BF算法需要在文本串T的每个位置上都尝试匹配模式串P,因此时间复杂度为O(n*m)

在实际情况下,BF算法的效率并不高,特别是当文本串T和模式串P的长度很大时。对于较长的文本串和模式串,BF算法的时间复杂度可能会导致性能问题。

那么有没有另外一种解法,可以避免不必要的i回溯,而只移动j即可呢?这样所需要消耗的时间就会大大减少。

答案就是KMP算法。

KMP算法

KMP算法的核心思想是利用模式串自身的特点来加速匹配过程,避免重复匹配。

算法步骤

我们设主串和模式串中的字符位置分别为ij

  • 如果当前字符匹配成功(即T[i] == P[j]),步骤与暴力匹配法相同,则i++,j++,继续匹配下一个字符;
  • 如果当前字符匹配失配(即T[i]! = P[j]),则根据最大长度表计算需要移动的位数。

这里由于匹配成功的情况与前面BF相同,所以我们只对匹配失败进行讨论。

公式

需要移动的位数=已匹配的字符数-失配字符的上一位字符对应的最大长度

这里我们理解一下具体的步骤,以及为什么是上述的公式。

为什么是算出最大长度的相同前缀和后缀

因为当最大长度的前缀和后缀相同的时候,移动已匹配的字符数-最大长度即可保证不会多移动或者少移动。如图:

在这里插入图片描述

蓝色部分的字符个数即是我们需要移动的字符个数,而黄色部分的字符个数即是最大相同长度,而黄色+蓝色部分即是

已匹配的字符个数

所以有:已匹配的字符个数=最大相同长度+需要移动的字符个数,从而得出:

需要移动的字符个数=已匹配的字符个数-最大相同长度

注意:我们要找的是相同前后缀的最长长度,注意一定是要最长的。并且不能是字符串本身。(如果是本身便没有意义了)

最大长度表是什么

上述过程我们所提到的最大长度表指的是模式串中最大长度的相同前缀和后缀,在公式中的最大相同长度就是对照该表得出的。

在这里插入图片描述

如何求最大长度表呢?在具体的代码中,我们需要使用一个函数来求出最大长度表,并且在具体的算法实现中,让其对应求出所需要移动的字符个数。这个时候我们就需要用到next数组


next数组

首先我们最需要知道的是:next数组的作用就是求出最大长度表。

最大长度表并不是使用next数组求出来的对照表,而是指的是next数组本身。next数组存储的是最大长度表,用于帮助算法快速定位匹配位置;

而由于数组的初始下标为0的限制,在书写上两者会有以下的差异:

next 数组相当于“最大长度值” 整体向右移动一位,然后初始值赋为-1。(因为数组的初始下标为0)

也就是 j-next[j]

在这里插入图片描述

问题的关键就是寻找模式串中最大长度的相同前缀和后缀,找到了模式串中每个字符之前的前缀和后缀公共部分的最大长度后,便可基于此匹配。而这个最大长度便正是next 数组要表达的含义。

next的具体求法

针对主串和模式串来进行字符匹配,而p[k]是主串正在被匹配的子字符串的元素,p[j]是正在进行匹配的模式串的元素。

  • 如果模式串的第i个字符和第j个字符相等(即p[k ] == p[j]),则next[j + 1] = next[j] + 1 = k + 1,同时i和j都向后移动一位。

也就是说此时:t(1)t(2)…t(k)=t(j-k+1)t(j-k+2)…t(j)

那么next[j + 1] = next[j] + 1 = k + 1。代表此字符前的模式串中,有长度k+1 的相同前缀后缀。

  • 如果模式串的第i个字符和第j个字符不相等(即p[k ] ≠ p[j]),则next[ j + 1 ] = next[k] + 1,否则继续递归前缀索引k = next[k],而后重复此过程。 也就是说此时正在匹配的字符失配,而算出的next[ j + 1 ] = next[k] + 1就是最大长度。

注意:主串是永远不动的,动的一直都是子串也就是模式串,也就是说i永不递减,只有j会递减。

next数组的代码使用递推求解,好处在于会不断利用已掌握的信息来避免重复的运算。

针对上述的字符不相同的情况,我们对此进行更详细的解答。

首先我们应该以一种类动态规划的思想去思考这个问题:动态规划中,我们会利用已知的子问题来解决更大规模的问题,避免重复的计算;而在KMP中,next数组存储了模式串中的最大长度,这个最大长度会帮助我们跳过一些不必要的比较,这个在后面会提到。

接下来,我们进行模拟。

当匹配不成功时:

查找是否存在更短的共同前后缀,如果找到了,则重新从此处再做一次KMP算法

例如,有以下字符串:

A  B  A  C  A  B  A  B
0  1  2  3  4  5  6  7

扫描到 6 号位的 A 时,最长公共前后缀是 ABA;而扫描到 7 号位的 B 时,ABAC 和 ABAB 不匹配了,即原来的最长公共前后缀失配。

这时候我们要做的事情就是,找上一次匹配中次长的公共前后缀,看与 7 号位的 B 拼接起来是否能匹配。因为我们的目的就是为了继续匹配,但是由于最长的已经用过了,所以就找次长的。

这时候,注意到上一次扫描中 0 ~ 2 位的 ABA 是和 4 ~ 6 位的 ABA 完全相同的,所以考察上一次匹配中次长的公共前后缀,只能在考察上一次匹配中的最长公共前后缀中寻找,也就是说,只能考察 ABA 中更短的 BA、A 是否是次长的,而这直接在前面一个 ABA 中考察就行(因为前后两个ABA是一样的)。(我们的目的就是要找最长公共前后缀)

所以我们把 ABA C ABA 的中间部分(C)和后缀(ABA)直接抛弃,等效于一个串 ABA(也就是前缀)与 B 拼接成 ABAB。这样再来计算第 7 位的 B 的 next 值,等价于计算 ABAB 第 3 位的 B 的 next 值。

代码演示
void GetNext(char* p,int next[])
{
	int pLen = strlen(p);
	next[0] = -1;
	int k = -1;
	int j = 0;
	while (j < pLen - 1)
	{
		//p[k]表示前缀,p[j]表示后缀
		if (k == -1 || p[j] == p[k]) 
		{
			++k;
			++j;
			next[j] = k;
		}
		else 
		{
			k = next[k];
		}
	}
}

这样我们就能计算出我们需要的next值,从而得到最大长度表,然后再将该表代入到需要移动字符数的计算公式中,继续匹配下去。

当然

接下来根据KMP算法的主要核心以及next数组举例介绍流程:

假设我们有文本串 T = "ABCABABCABD" 和模式串 P = "ABCABD"。我们需要在文本串 T 中找到模式串 P 的出现位置。

步骤1: 构建next数组

首先,我们需要为模式串 P 构建一个next数组。这个数组用于在不匹配的情况下,告诉我们应该从模式串的哪个位置重新开始匹配。

对于模式串 P = "ABCABD",我们如下构建next数组:

  1. 初始化:next[0] = -1 (当模式串的第一个字符不匹配时,我们没有更早的位置可以回退到)
  2. P[1] 开始,比较前后缀:
    • j = 0next[1] = 0 (没有相同的前后缀)
    • j = 1,比较 P[0]P[1],不相同,next[2] = 0
    • j = 2,比较 P[0]P[2],不相同,next[3] = 0
    • j = 3,比较 P[1]P[3],相同,next[4] = 1
    • j = 4,比较 P[2]P[4],相同,next[5] = 2
    • j = 5,比较 P[3]P[5],不相同,next[6] = 0

最终的next数组为 [-1, 0, 0, 0, 1, 2, 0].

步骤2: 使用next数组进行匹配

现在我们使用next数组来匹配文本串 T 和模式串 P

T = ABCABABCABD
P = ABCABD
  1. 初始位置:i = 0, j = 0
    • T[0] = P[0] (A = A),匹配,i = 1, j = 1
    • T[1] = P[1] (B = B),匹配,i = 2, j = 2
    • T[2] = P[2] (C = C),匹配,i = 3, j = 3
    • T[3] = P[3] (A = A),匹配,i = 4, j = 4
    • T[4] = P[4] (B = B),匹配,i = 5, j = 5
    • T[5] = P[5] (C ≠ D),不匹配,根据 next[5] = 2j = 2
  2. 继续匹配:
    • T[5] = P[2] (C = C),匹配,i = 6, j = 3
    • T[6] = P[3] (A = A),匹配,i = 7, j = 4
    • T[7] = P[4] (B = B),匹配,i = 8, j = 5
    • T[8] = P[5] (D = D),匹配,i = 9, j = 6(模式串匹配完成)

匹配成功,模式串 P 在文本串 T 中的起始位置为 3 (从0开始计数)。

通过这个例子,我们可以看到KMP算法如何有效地使用next数组来避免不必要的比较,从而加快字符串匹配的过程。

nextval(next的扩展优化)

请看以下举例

T = AAABAAAAB
P = AAAAB

当i=4,j=4时,我们发现此时的字符不匹配,那么根据next[j]的指示我们还需进行:i=4不变,分别j=3、j=2、j=1的三次比较。

但是实际上模式串中的13以及第4个字符全都相等,因此将13这3个字符再去和主串的第4个字符比较实际上是和j=4时的情况是一样的,是会失配的。

在这里插入图片描述

那么我们应该如何避免并跳过这种重复的比较,直接进行i=5、j=1的比较呢?

这里则可以对next进行优化得到nextval

//优化过后的next 数组求法
void GetNextval(char* p, int next[])
{
	int pLen = strlen(p);
	next[0] = -1;
	int k = -1;
	int j = 0;
	while (j < pLen - 1)
	{
		//p[k]表示前缀,p[j]表示后缀  
		if (k == -1 || p[j] == p[k])
		{
			++j;
			++k;
			//较之前next数组求法,改动在下面4行
			if (p[j] != p[k])
				next[j] = k;   //之前只有这一行
			else
				//因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
				next[j] = next[k];
		}
		else
		{
			k = next[k];
		}
	}
}

这个代码就完美地规避了上述讲到的问题。nextval可以实现跳跃到一个更远的位置进行匹配,从而减少不必要的比较次数。


接下来的代码是整个KMP算法的代码

代码演示

int KmpSearch(char* s, char* p)
{
	int i = 0;
	int j = 0;
	int sLen = strlen(s);
	int pLen = strlen(p);
	while (i < sLen && j < pLen)
	{
		//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++    
		if (j == -1 || s[i] == p[j])
		{
			i++;
			j++;
		}
		else
		{
			//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]    
			//next[j]即为j所对应的next值      
			j = next[j];
		}
	}
	if (j == pLen)
		return i - j;
	else
		return -1;
}

时间复杂度

KMP算法的时间复杂度分析如下:

  1. 构建next数组的时间复杂度:构建next数组的时间复杂度是O(m),其中m是模式串的长度。

  2. 匹配过程的时间复杂度:在KMP算法中,匹配过程的时间复杂度主要取决于文本串的长度n。在匹配过程中,每次失配时,根据next数组回退到一个更早的位置重新开始匹配,而不会重复比较已经匹配过的字符。因此,匹配过程的时间复杂度是O(n)。

综合以上两点,KMP算法的总体时间复杂度为O(m + n),其中m是模式串的长度,n是文本串的长度。相比于朴素的字符串匹配算法的**O(m*n)**时间复杂度,KMP算法通过利用next数组的特性,在匹配过程中避免了不必要的比较,从而实现了更高效的字符串匹配。

KMP的使用场景

总的来说,KMP算法适用于需要快速匹配模式串的场景,特别是在文本串较长、模式串较短的情况下。为什么呢?我们参照KMP的时间复杂度,O(m + n)m是模式串的长度,n是文本串的长度:

  • 长文本串(针对n):KMP算法适用于处理长文本串,因为它能够在匹配过程中避免不必要的比较,从而减少比较次数,提高匹配效率。
  • 短模式串(针对m):KMP算法在处理短模式串时效果显著,因为其时间复杂度不会随着模式串长度的增加而大幅增加。
  • 需要多次匹配:如果需要在同一文本串中多次匹配同一个模式串,KMP算法可以提高效率,因为构建好的next数组可以被重复利用。

常用用途

  • 字符串搜索:KMP算法常用于在文本串中搜索特定的模式串,例如搜索关键字、词语等。

  • 文本处理:在文本处理领域,KMP算法可以用于文本匹配、替换等操作。

  • 编译器设计:在编译器的词法分析阶段,KMP算法用于匹配词法单元,如关键字、标识符等。

  • 网络协议:在网络协议中,KMP算法可以用于匹配特定的模式,例如在URL匹配、数据包匹配等场景中。
    *是文本串的长度:

  • 长文本串(针对n):KMP算法适用于处理长文本串,因为它能够在匹配过程中避免不必要的比较,从而减少比较次数,提高匹配效率。

  • 短模式串(针对m):KMP算法在处理短模式串时效果显著,因为其时间复杂度不会随着模式串长度的增加而大幅增加。

  • 需要多次匹配:如果需要在同一文本串中多次匹配同一个模式串,KMP算法可以提高效率,因为构建好的next数组可以被重复利用。

常用用途

  • 字符串搜索:KMP算法常用于在文本串中搜索特定的模式串,例如搜索关键字、词语等。
  • 文本处理:在文本处理领域,KMP算法可以用于文本匹配、替换等操作。
  • 编译器设计:在编译器的词法分析阶段,KMP算法用于匹配词法单元,如关键字、标识符等。
  • 网络协议:在网络协议中,KMP算法可以用于匹配特定的模式,例如在URL匹配、数据包匹配等场景中。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构(邓俊辉)学习笔记】向量02——动态空间管理

文章目录 1. 概述2. 静态空间管理缺点3. 动态空间管理3.1 扩容3.1.1 如何实现扩容3.1.2 扩容算法3.1.3 容量递增策略 VS 容量倍增策略3.1.3.1 容量倍增策略分摊分析3.1.3.2 容量递增策略分摊分析3.1.3.3 结果对比 3.2缩容3.2.1 动态缩容算法实现3.2.2 动态缩容算法时间复杂度 4…

2024最新Nessus 免费安装 附详细安装教程

免责声明 请勿利用文章内的相关技术从事非法测试。由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任&#xff0c;请遵守网络安全法律。本次仅用于测试&#xff0c;请完成测试后24小时之…

C++程序在Windows平台上各种定位内存泄漏的方法

一、前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏&#xff0c;因为Linux在开发领域的使用场景大多是跑服务器&#xff0c;再加上它的开源属性&#xff0c;相对而言&#xff0c;处理问题容易形成“统一”的标准。而在Windows平台&#xff0c;服务器和客户端…

用docker方式安装openGauss数据库的事项记录

文章目录 &#xff08;一&#xff09;背景&#xff08;二&#xff09;安装&#xff08;2.1&#xff09;安装docker&#xff08;2.2&#xff09;安装openGauss &#xff08;三&#xff09;运行&#xff08;3.1&#xff09;运行openGauss镜像&#xff08;3.2&#xff09;连接open…

区块链技术与应用学习笔记(5-7节)——北大肖臻课程

​ 目录 ​BTC实现 基于交易的账本模式&#xff1a; UTXO集合&#xff1a; 交易费用&#xff1a; BTC网络 1.应用层&#xff1a; 2.网络层&#xff1a; 3传播层&#xff1a; 什么是鲁棒&#xff1f; BTC挖矿&#xff1a; 出块奖励&#xff1a; 挖矿难度调整&#…

Centos安装/更新Docker

首先要配置好Centos 配置好静态IP 替换yum源为阿里云 Docker是什么&#xff1f; Docker 是一种开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后部署到任何流行的 Linux 机器上。是一种虚拟化的技术&#xff0c;可以把…

基于socket编程实现TCP和UDP的通信流程

socket编程的常用函数&#xff0c;可以参考以下这篇博客 socket编程-----常用socket编程函数https://blog.csdn.net/ZZZCY2003/article/details/138071210 关于TCP的三次挥手、四次挥手过程和UDP的报文分析可以参考以下两篇博客 计算机网络--运输层https://blog.csdn.net/ZZ…

深度学习-N维数组和访问元素

目录 N维数组访问元素 N维数组 N维数组是机器学习和神经网络的主要数据结构 访问元素 最后一个子区域中的::是跳的意思&#xff0c;这个区域说明的是从第一个元素&#xff08;即第一行第一列那个&#xff09;对行开始跳3下循环下去直到行结束、对列开始跳2下循环下去直到列…

如何解决IntelliJ IDEA 2024打开项目时频繁闪退问题

&#x1f42f; 如何解决IntelliJ IDEA 2024打开项目时频繁闪退问题 &#x1f43e; 文章目录 &#x1f42f; 如何解决IntelliJ IDEA 2024打开项目时频繁闪退问题 &#x1f43e;摘要引言正文&#x1f4d8; 识别问题&#x1f4d9; 内存配置调整步骤1: 定位vmoptions文件步骤2: 修改…

C++初阶之入门

零、什么是C C是基于C语言而产生的&#xff0c;它既可以进行C语言的过程化程序设计&#xff0c;又可以进行以抽象数据类型为特点的基于对象的程序设计&#xff0c;还可以进行面向对象的程序设计。 C缺点之一&#xff0c;是相对许多语言复杂&#xff0c;而且难学难精。许多人说学…

为什么g++编译后的cpp文件名字为a,out

文章目录 为什么g编译后的cpp文件名字为a,out能修改默认名变成cpp文件名吗关于作者 为什么g编译后的cpp文件名字为a,out 在使用g编译C源代码时&#xff0c;默认情况下生成的可执行文件名为 a.out。这是由于在Unix和类Unix系统上&#xff0c;编译器的默认行为是将生成的可执行文…

可视化+多人协同技术原理和案例分享

前言 hi&#xff0c;大家好&#xff0c;我是徐小夕&#xff0c;之前和大家分享了很多可视化低代码的技术实践&#xff0c;最近也做了一款非常有意思的文档搭建引擎——Nocode/Doc&#xff1a; 也做了一些分享&#xff1a; Nocode/Doc&#xff0c;可视化 零代码打造下一代文件编…

Unity读书系列《Unity3D游戏开发》——脚本(一)

文章目录 前言一、脚本模版及其拓展1、脚本模版2、拓展脚本模版 二、脚本的生命周期三、脚本的执行顺序四、脚本序列化1、序列化数据2、serializedObject3、监听部分元素修改事件 五、定时器与间隔定时器六、工作线程&#xff08;多线程&#xff09;总结 前言 脚本在Unity的重…

Rust HTTP 客户端:易于使用、功能强大 | 开源日报 No.228

seanmonstar/reqwest Stars: 8.9k License: Apache-2.0 reqwest 是一个易于使用且功能强大的 Rust HTTP 客户端。 异步和阻塞客户端支持普通数据、JSON、urlencoded 和 multipart 数据格式可定制的重定向策略支持 HTTP 代理和系统原生 TLS 或 rustls 的 HTTPSCookie 存储功能…

RoadBEV:鸟瞰图中的道路表面重建

1. 代码地址 GitHub - ztsrxh/RoadBEV: Codes for RoadBEV: road surface reconstruction in Birds Eye View 2. 摘要 本文介绍了RoadBEV&#xff1a;鸟瞰图中的道路表面重建。道路表面条件&#xff08;特别是几何形状&#xff09;极大地影响了自动驾驶汽车的驾驶性能。基于…

就业班 第三阶段(nginx) 2401--4.22 day1 nginx1 http+nginx初识+配置+虚拟主机

一、HTTP 介绍 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写,是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。 HTTP是一个基于TCP/IP通信协议来传递数据&#xff08;HTML 文件…

ubuntu安装Qv2ray2.7.0及配置

需要下载两个文件&#xff0c;一个是zip文件&#xff0c;一个是AppImage执行程序。 执行AppImage需要先下载fuse sudo apt install libfuse2然后为AppImage赋予执行权限 sudo chmod x ./Qv2ray-v2.7.0-linux-x64.AppImage执行,执行前可以解压zip文件 ./Qv2ray-refs.tags.v1…

操作系统(Operating System)知识点复习——第十一章 I/O管理与磁盘调度

目录 0.前言 1.I/O设备 2.I/O功能的组织 3.Operating System Design Issues 4.I/O缓冲 4.1 单缓冲Single Buffer 4.2 双缓冲Double Buffer 4.3 循环缓冲 5.磁盘调度Disk Scheduling 5.1 磁盘性能参数 5.2 磁盘调度策略 ①First-in&#xff0c;first-out(FIFO) ②Pr…

鸿蒙ArkUI实战开发-如何通过上下滑动实现亮度和音量调节

场景说明 在音视频应用中通常可以通过上下滑动来调节屏幕亮度和音量大小&#xff0c;本例即为大家介绍如何实现上述UI效果。 说明&#xff1a; 由于当前亮度和音量调节功能仅对系统应用开发&#xff0c;所以本例仅讲解UI效果的实现。 效果呈现 本例效果如下&#xff1a; 当在…

决策树分析及其在项目管理中的应用

决策树分析是一种分类学习方法&#xff0c;其主要用于解决分类和回归问题。在决策树中&#xff0c;每个内部节点表示一个属性上的测试&#xff0c;每个分支代表一个属性输出&#xff0c;而每个叶节点则代表类或类分布。通过从根节点到内部节点的路径&#xff0c;可以构建一系列…