基于分治法的求最大最小问题

问题描述,在一个数组中的所有数据均成无序排序,编程实现求取数组中的最大数值与最小数值,要求是时间复杂度越小越好,

且元素的比较的次数越小越好。


在学习分而治之算法思想之前,通常我们使用的编程语句如下:


//method for find max and min in array


void minMax ( int A [] , int &min , int &max , int n )
{
	min = A[0];
	max = A[0] ;
	for ( int i = 1 ; i < n ; i++ )
	{
		if ( A[i] > max )
		{
			max = A[i] ;
		}
		if ( A[i] < min )
		{
			min = A[i] ;
		}
	}
}

这种实现方法中时间复杂度是 O(n) ,即算法在执行的时候,对数组A中的所有元素进行扫描一次即可,

对于元素的比较次数是 2n -2 其中数值 n 表示的是数组 A 中元素的个数, 2n -2 这个数值是如何得到的呢? 

这个简单, 首先对应在算法开始的时候对数据 min , max 进行初始化的时候, 对应将数组 A 中的首个元素进行访问,

接下来对数组 A 中的 n-1 个元素进行扫描和比较, 扫描元素的个数是 n-1 ,并且每次扫描一个元素,就会将这个元素

分别于 min 和 max 两个数据值进行 2 次的比较操作, 所以一次扫描下来,总的比较次数是 2*(n-1) = 2n -2 次。


下面在使用分治法来找出最大最小元素之前,我们先来看一下,分而治之法的算法思想吧。


对于分而治之法的设计原理就是,对于一个规模为 n 的问题 P(n) , 我们可以将这个大问题分解为 k 个规模较小的子问题, 

{P(1), P(2) , ....., P(k) }这些子问题互相是独立的,并且对应的结构与大问题 P(n) 的结构是相同的。在求解这些子问题的时候,

又可以对其进行更细一步的分解,一直到分解到某一个阈值  n0 才停止分解, 而对应的达到阈值的问题规模刚好是可以

通过题目中的描述进行求解的问题规模大小,于是将分解的子问题各自进行求解, 然后再通过相应的合并函数将这些

求得的子问题的解进行合并, 所得到的合并的解,即为规模为 n 的问题 P(n) 的解。


即,


P(n) -> { P(1) , P(2) , ... , P(k)}


for i = 1 --> k

{

   yi <- func (  P(i) ) 

}



yn  <-- merge( y 1 , y2, ... yk )


yn  即是 P(n) 问题的解


其中上述的三段伪代码分别代表的是,在分治法中的三个重要的步骤: 1. 划分步骤  2. 治理步骤 3. 组合步骤

在划分步骤中, 通常是将输入的问题根据问题的描述和给定的阈值,划分成 k 个子问题 ; 一般来说通常是将这 k 个问题

划分成结构和模式相同的方式,这一点比较重要,因为相同的结构利于后续递归方法的调用,和边界条件的计算。。


在治理步中,治理步是分治法的核心所在,通常在将问题分解到达到某一个设定阈值的时候,就会将停止对这个问题继续向下划分,

并这个问题的甩给治理步骤的函数调用中来计算该子问题的解。

而之所以说治理步骤是很重要的,也是因为治理步骤是否执行,是完全取决于这个分治法中的阈值的选取的,而对于分而治之方法

中阈值的选取对算法的性能影响是很大的,所以又很多人在研究对于分而治之方法中阈值的选取这个方向的。


在统计步,统计步也叫做组合步,在这个步骤中主要进行的工作就是,将上述分解的 k 个子问题进行组合起来,使之合并之后的解

为所求的大规模问题的解。


这三个步骤是很重要的,不仅仅是因为对于这些步骤的划分将比较晦涩难懂的分治法,进行了量化,使我们在解决分治法问题的时候,

有了一套比较完整的思考方向,而且更值得学习的是,这三个步骤分别影响了一个分治法的时间复杂度。


下面我们来看一下,对于一个分治法的通用时间复杂度的求解方程


f(1) =1  (a)
f(n) = kf(n/k) + bn  ; n>1 (b) 

分而治之算法所消耗的时间 与其中治理步骤中的子算法, 组合步骤中的组算法,以及划分的子问题的个数 k 之间有着很密切的关系。

其中治理步骤中的子算法决定的是递归方程中的初始值 ,即 f( initial ) =  initial value  ---(a) .

而组合步骤中的子算法决定的是递归方程中的非齐次项的大小 。

同时对于阈值 n0 的选取决定的是将整个的问题划分成子问题的个数 : k , 其中子问题的个数决定了递归方程低阶项的系数。


好了,上面的就是分治法中比较重要的求解分析方法,下面来看一下如何使用分治法来求取一个数组中的最大最小项,以一种比较次数更少的方式:


//method for find max and min in array

#include <cstdio>
#include <cstdlib>


void minmax ( int A [] , int &min , int &max , int low , int high )
{
	int mid , x1 ,y1 , x2 , y2 ;

	if ((high-low) <= 1)
	{
		if ( A[high] > A[low] )
		{
			min = A[low] ;
			max = A[high] ;
		}

		else
		{
			max = A[low] ;
			min = A[high] ;
		}
	}

	else
	{
		mid = (low+high)/2 ;

		minmax(A , x1 , y1 , low , mid ) ;
		minmax( A , x2 , y2 , mid+1 , high) ;

		min = min_(x1 , x2) ;
		max = max_( y1 , y2 ) ;
	}
}

int main ( void )
{
	int A [] = {8 , 3 , 6 , 2 , 1 , 9 , 5 ,4,21} ;

	int min__ , max__ ;
	minmax(A , min__ , max__ , 0 , 8) ;
	printf("here is the min %d  , here is the max :%d ", min__ , max__) ;

	system("pause") ;

	return 0 ;
}



对于上述算法的总的比较次数的分析是:


C(2) = 1
C(n) = 2*C(n/2) +2 


上述的方程是整个算法所基于的递归方程,通过求解方程可以得到 C(n) = 3/2* n -2 ,所以从整体上减少了比较的次数。












<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值