不使用第三个变量交换两个变量的值
不使用第三个变量交换两个变量的值
通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下:int a,b;
a=10; b=15;
int t;
t=a; a=b; b=t;
这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。
上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?这里我们可以用三种算法来实现:1)算术运算;2)指针地址操作;3)位运算。
1)算术运算
简单来说,就是通过普通的+和-运算来实现。代码如下:
int a,b;
a=10;b=12;
a=b-a; //a=2;b=12
b=b-a; //a=2;b=10
a=b+a; //a=10;b=10
通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯标准算法之后。
它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。
具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。
此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法)
2)指针地址操作
因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即:
int *a,*b; //假设
*a=new int(10);
*b=new int(20); //&a=0x00001000h,&b=0x00001200h
a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h
b=(int*)(b-a); //&a=0x00000200h,&b=0x00001000h
a=(int*)(b+int(a)); //&a=0x00001200h,&b=0x00001000h
通过以上运算a、b的地址真的已经完成了交换,且a指向了原先b指向的值,b指向原先a 指向的值了吗?上面的代码可以通过编译,但是执行结果却令人匪夷所思!原因何在?
首先必须了解,操作系统把内存分为几个区域:系统代码/数据区、应用程序代码/数据区、堆栈区、全局数据区等等。在编译源程序时,常量、全局变量等都放入全局数据区,局部变量、动态变量则放入堆栈区。这样当算法执行到“a=(int*)(b-a)”时,a的值并不是0x00000200h,而是要加上变量a所在内存区的基地址,实际的结果是:0x008f0200h,其中0x008f即为基地址,0200即为a在该内存区的位移。它是由编译器自动添加的。因此导致以后的地址计算均不正确,使得a,b指向所在区的其他内存单元。再次,地址运算不能出现负数,即当a 的地址大于b的地址时,b-a<0,系统自动采用补码的形式表示负的位移,由此会产生错误,导致与前面同样的结果。
有办法解决吗?当然!以下是改进的算法:
if(a
{
a=(int*)(b-a);
b=(int*)(b-(int(a)&0x0000ffff));
a=(int*)(b+(int(a)&0x0000ffff));
}
else
{
b=(int*)(a-b);
a=(int*)(a-(int(b)&0x0000ffff));
b=(int*)(a+(int(b)&0x0000ffff));
}
算法做的最大改进就是采用位运算中的与运算“int(a)&0x0000ffff”,因为地址中高16位为段地址,后16位为位移地址,将它和0x0000ffff进行与运算后,段地址被屏蔽,只保留位移地址。这样就原始算法吻合,从而得到正确的结果。
此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内存中是没有移动过的。(以下称为地址算法)
3)位运算
通过异或运算也能实现变量的交换,这也许是最为神奇的,请看以下代码:
int a=10,b=12; //a=1010^b=1100;
a=a^b; //a=0110^b=1100;
b=a^b; //a=0110^b=1010;
a=a^b; //a=1100=12;b=1010;
此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。
即:a^b^b=a。将a=a^b代入b=a^b则得b=a^b^b=a;同理可以得到a=b^a^a=b;轻松完成交换。
以上三个算法均实现了不借助其他变量来完成两个变量值的交换,相比较而言算术算法和位算法计算量相当,地址算法中计算较复杂,却可以很轻松的实现大类型(比如自定义的类或结构)的交换,而前两种只能进行整形数据的交换(理论上重载“^”运算符,也可以实现任意结构的交换)。
《c语言程序设计》--4种“交换算法”介绍。
第 1 页 共 2 页 算法 交换 在很多问题的解决中都需要使用到交换这个方法,比如排序时,需要将两个变量的值互换等等。交换是指将两个变量的值进行互换。假设有整型变量a 和b ,分别存储整数2和6,如图01-01所示。要将变量a 和b 交换就意味着交换变量a 和变量b 中的值,使得变量a 存放变量b 交换前的值,而变量b 存放变量a 交换前的值,如图01-02所示。 图01-01 图01-02 语句“a=b; b=a;”是不能实现变量a 、b 交换的,只可能使得a 、b 最终都存放变量b 的值(大家可以编程试一试)。其原因是赋值操作具有覆盖性,执行a=b ;语句后,a 原来的值已经被覆盖了,此时a 最新的值就是b 的值,再实现b=a ;时,b 的值就是a 最新的值,也就是b 的值。 一、 中间变量法 要实现交换,最基本、最通用的方法是中间变量法。该方法的基本思路是定义第三个变量t ,用于暂时保存两个变量中的某一个变量的原值。具体实现代码如下: t = a; a = b; b = t; 交换过程请大家自己仿照图01-01自己给出。注意每一个变量画一个方框, 每执行一步后,改变被赋值变量的值。 【注意事项】 此处,中间变量t 可以暂存变量 a 的值也可以暂存变量 b 的值,不过一旦对变量t 的赋值语句确定后,后面两个赋值语句的顺序不是任意的。赋值顺序的记忆可总结为“t 中暂存的变量先被赋值”。即t = a; a = b; b = t;或者t = b; b = a; a = t;。
二、算术加减法 对于数值型数据还可以采用算术加减法来实现交换,其基本思想是以a获得b的值,以b获得a的值作为目标,进行加减运算,从而完成交换。具体实现可用如下代码: a = a+b; b = a-b; a = a-b; 三、思考与练习 1. 请编写程序验证“交换”算法。 2. 请编写程序验证“交换”算法,要求“交换”算法使用函数来实现。 3. 请大家思考一下,使用算术加减法实现的“交换”算法有什么限制? 4. 请大家思考一下,我们能不能使用乘除法来实现“交换”算法?如果可 以,那么具体代码如何来编写呢?使用乘除法来实现“交换”算法,有 什么限制呢? 5. 拓展 两个变量(一般为整型或字符型)的交换还可以使用“异或”运算符。 具体步骤如下: int a,b; a=a^b; b=a^b; a=a^b;
两个变量交换值
不使用第三方变量交换两个变量的值(c#)2009-07-22 16:47这需要进行位操作,必较麻烦的, 在学习程序语言和进行程序设计的时候,交换两个变量的值是经常要使用的。通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下: int a,b; a=10; b=15; int t; t=a; a=b; b=t; 这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。 上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?答案是肯定的!这里我们可以用三种算法来实现:1)算术运算;2)指针地址操作;3)位运算。 1)算术运算 简单来说,就是通过普通的+和-运算来实现。代码如下: int a,b; a=10;b=12; a=b-a; //a=2;b=12 b=b-a; //a=2;b=10 a=b+a; //a=10;b=10 通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯标准算法之后。 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法) 2)指针地址操作 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即: int *a,*b; //假设 *a=new int(10); *b=new int(20); //&a=0x00001000h,&b=0x00001200h a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h b=(int*)(b-a); //&a=0x00000200h,&b=0x00001000h a=(int*)(b+int(a)); //&a=0x00001200h,&b=0x00001000h 通过以上运算a、b的地址真的已经完成了交换,且a指向了原先b指向的值,b指向原先a 指向的值了吗?上面的代码可以通过编译,但是执行结果却令人匪夷所思!原因何在? 首先必须了解,操作系统把内存分为几个区域:系统代码/数据区、应用程序代码/数据区、
运筹学题(交二)
第一章 1,(决策变量)(目标函数)及(约束条件)构成。称为三个要素, 2解决问题的目标函数是多个决策变量的线性函数,通常是求(最大值)或(最小值) 3一般地,假设线性规划数学模型中,有m个约束,有n个决策变量xj, j=1,2…,n,目标函数的变量系数用cj表示, cj称为(价值系数)。 约束条件的变量系数用aij表示,aij称为(工艺系数)。约束条件右端的常数用bi表示, bi称为(资源限量)。 4线性规划的解的四种形式:(有唯一最优解),(有无界解),(有多重解),(无可行解)。 5线性规划问题的标准型的形式,下列选项表述不正确的是(C)A.目标函数求最大值(有时求最小值) B.约束条件都为等式方程; C.变量xj为正数。 D.常数bi都大于或等于零; 6凸集的几何特征:(连接凸集中任意两点的线段仍在此集合内)。7.单纯形法求解时一定要将数学模型化为(标准型)。 8.当确定某一矩阵为基矩阵时,则基矩阵对应的列向量称为(基向量),其余列向量称为(非基向量) 9.对某一确定的基B,令非基变量等于零,利用式AX=b 解出基变量,则这组解称为基B的(基本解)
10.若线性规划可行解K非空,则K是(凸集). 11.线性规划的可行解集合K的点X是极点的充要条件为(X是基本可行解). 12.在单纯形方法中,求初始基可行解,列出初始单纯形表,求出检验数。其中(基变量)的检验数必为零; 13.在用单纯形法计算过程中,若存在一个σk >0,σk所对应的变量xk的系数列向量Pk 0,则该线性规划问题(没有有限最优解)。 14.单纯形计算方法中,是先找换出变量,还是先找换入变量? 答,先找换入变量。 15.进行旋转运算是指:在确定了换入变量和换出变量后,要把换入变量所对应的系数列向量变成(单位向量) 第二章 1.在互为对偶的一对原问题与对偶问题中,不管原问题是求极大或极小,原问题可行解目标函数值一定不超过其对偶问题尅星界的目标函数值。(错) 2.任何线性规划问题具有唯一的对偶问题(对) 3.若原问题可行且另一个问题不可行,则原问题(A) A.有无界解 B.有可行解 C.可能有可行解也可能没有 4.简述单纯形法与对偶单纯形法的区别 5.简述求原问题的对偶问题的方法 6.两个线性规划互为对偶式时,则原问题的目标值不超过对偶问题的
变量交换的几种常见方法
变量交换的几种常见方法 前几天发现了一个问题:有人告诉我,要进行变量交换,就必须引入第三变量! 假设我们要交换a和b变量的值,如果写成 int a=5,b=10; a=b; b=a; 那么结果就是两个都是10,理由不言而喻。 所以就应该引入第三变量,在a的值被覆盖之前就把a的值保留好。int a=5,b=10,tmp; tmp=a; a=b; b=tmp; 这样,就要引入了第三个变量,然而,我们能不能不引入第三变量来实现变量交换呢? 答案自然是肯定的,首先我们可以这样设想,如果a的值被覆盖了,那么就没法知道b应该放什么值了, 所以,我们要保留a的值,因此我们可以把a和b的值合起来,放在a里,再把合起来的值分开,分别放到b和a中:
int a=5,b=10; a=a+b; //a=15,b=10 b=a-b; //a=15,b=5 a=a-b; //a=10,b=5 但是这样做有一个缺陷,假设它运行在vc6环境中,那么int的大小是4 Bytes,所以int变量所存放的最大值是2^31-1即2147483647,如果我们令a的值为2147483000,b的值为1000000000,那么a和b 相加就越界了。 事实上,从实际的运行统计上看,我们发现要交换的两个变量,是同号的概率很大,而且,他们之间相减,越界的情况也很少,因此我们可以把上面的加减法互换,这样使得程序出错的概率减少: int a=5,b=10; a-=b; //a=-5,b=10 b+=a; //a=15,b=5 a+=b; //a=10,b=5 通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯引入第三变量的算法之后。 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a-=b”求出ab两点的距离,并且将其保存在a 中;第二句“b+=a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a+=b”求出b到原点
交换两个变量值
//【习3.1】交换两个变量值问题讨论。 public class Swap { // ①不能实现交换两个变量值的方法 public static void swap(int x, int y) { int temp = x; x = y; y = temp; } public static void swap(Object x, Object y) //不行 { Object temp = x; //两个对象之间的赋值是引用赋值,传递的是引用,即变量的地址 x = y; //改变形式参数x的引用,而未能改变实际参数的值, y = temp; //相当于改变了指针的值,而未改变通过指针指向的变量值 } //交换了,但改变的值没有带回 // ②能够交换两个数组元素值 public static void swap(int[] table, int i, int j) // 交换数组中下标为i、j的元素 { if (table != null && i >= 0 && i < table.length && j >= 0 && j < table.length && i != j) // 判断i、j是否越界 { int temp = table[j]; table[j] = table[i]; table[i] = temp; } } public static void swap(Object[] table, int i, int j) //交换数组中下标为i、j的元素 { if (table != null && i >= 0 && i < table.length && j >= 0 && j < table.length && i != j) //判断i、j是否越界 {
复习题2(算法部份)
第1章计算机和算法 1.使用计算机解题的步骤,以下描述正确的是:_____。 A.正确理解题意→设计正确算法→寻找解题方法→编写程序→调试运行 B.正确理解题意→寻找解题方法→设计正确算法→编写程序→调试运行 C.正确理解题意→寻找解题方法→设计正确算法→调试运行→编写程序 D.正确理解题意→寻找解题方法→设计正确算法→编写程序→调试运行 答案:B 2.计算机是一种按照设计好的程序,快速、自动地进行计算的电子设备,计算机开始计算之前,必须把解决某个问题的程序存贮在计算机的_____中。 A.硬盘B.软盘C.内存D.CPU 答案:C 3.计算机程序由以下两部分即:_____组成。 A.执行部分和数据部分 B.数据部分和程序部分 C.指令部分和数据部分 D.程序部分和指令部分 答案:C 4.计算机程序由一系列指令构成,每条指令要求计算机执行_____动作。 A.一组B.二个C.一个D.一个以上 答案:C 5.计算机程序由指令部分和数据部分组成,其中数据部分用来存储_____。 A.计算所需的原始数据和计算的中间结果,不能存储计算的最终结果 B.计算所需的原始数据,不能存储计算的中间结果和计算的最终结果 C.计算的中间结果和计算的最终结果,不能存储计算所需的原始数据 D.计算所需的原始数据、计算的中间结果或最终结果 答案:D 6.人们在设计计算机程序时,_____。 A.只要考虑“数据的存贮”而不要考虑“计算的过程” B.不要考虑“数据的存贮”而只要考虑“计算的过程” C.必须同时考虑“数据的存贮”和“计算的过程” D.以上答案都错 答案:C 7.设计计算机程序时,要考虑“计算的过程”,其含义是在对解决问题的方法进行步骤化时,_____。 A.只要指出“动作”而不必指出“动作的次序” B.不必指出“动作”而只要指出“动作的次序” C.必须同时指出“动作”和“动作的次序” D.以上说法都正确 答案:C 8.算法的特征是:有穷性、_____、能行性、有0个或多个输入和有一个或多个输出。 A.稳定性B.确定性C.正常性D.快速性 答案:B
交换两个变量的值,不使用第三个变量的方法及实现
交换两个变量的值,不使用第三个变量的方法及实现: 附录中有C/C++代码: 通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下: int a,b; a=10; b=15; int t; t=a; a=b; b=t; 这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。 上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?答案是肯定的!这里我们可以用以下几种算法来实现:1)算术运算;2)指针地址操作;3)位运算;4)栈实现。 1)算术运算 int a,b; a=10;b=12; a=b-a; //a=2;b=12 b=b-a; //a=2;b=10 a=b+a; //a=12;b=10 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a 到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。 此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法)除了使用加、减法外,还可以使用乘、除法实现,实现代码如下: //if a=10;b=12; a=a*b; //a=120;b=12 b=a/b; //a=120;b=10 a=a/b; //a=12;b=10 缺点:是只能用于数字类型,字符串之类的就不可以了。a+b有可能溢出(超出int的范围),溢出是相对的,+了溢出了,-回来不就好了,所以溢出不溢出没关系,就是不安全。 2)指针地址操作 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单 元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即:int *a,*b; //假设 *a=new int(10); *b=new int(20); //&a=0x00001000h,&b=0x00001200h a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h
c 语言 交换两个变量的值
1. 交换两个变量的值:用两种方法: 1) main () (3-5-1a(3-5-1b) printf(“a,b=?”“a,b=?”); scanf(“%d,%d”“%d,%d”,&a,&b); pringf(“a=%d\tb=%d\n”“a=%d\tb=%d\n”,a,b) ; t=a;a=b;b=t; a=a+b;b=a-b;a=a-b; pringf(“a=%d\tb=%d\n”,a,b); pringf(“a=%d\tb=%d\n”,a,b); } /*利用第三变量*/ } /*利用自身*/ 3) 利用全局变量交换两个变量的值: int a=3,b=7; Qj-swap2 main() { swap () printf("%d,%d\n",x,y); } swap() { a=a+b;b=a-b;a=a-b} 4)利用指针变量交换两个变量的值: main () { int a=3,b=10,*pa=&a,*pb=&b; clrscr(); printf("a=%d\tb=%d\n",a,b); swap (pa,pb); printf("a=%d\tb=%d\n",*pa,*pb); } swap (int *x,int *y) { int *t; t=*x;*x=*y;*y=t; } 4)下列程序运行的结果: (1)int x=1,y=2; Qj-swap1 main () { int a=3,b=4; move(x,y);move(a,b); printf("%d, %d, %d, %d",x,y,a,b); } move(int p,int q) { int k ; k=p;p=q;q=k; }
算法设计与分析习题答案1-6章
习题1 1. 图论诞生于七桥问题。出生于瑞士的伟大数学家欧拉(Leonhard Euler ,1707—1783)提出并解决了该问题。七桥问题是这样描述的:一个人是否能在一次步行中穿越哥尼斯堡(现 在叫加里宁格勒,在波罗的海南岸)城中全部的七座桥后回到起点,且每座桥只经过一次, 图 1.7是这条河以及河上的两个岛和七座桥的 草图。请将该问题的数据模型抽象出来,并判断此问题是否有解。 七桥问题属于一笔画问题。 输入:一个起点 输出:相同的点 1, 一次步行 2, 经过七座桥,且每次只经历过一次 3, 回到起点 该问题无解:能一笔画的图形只有两类:一类是所有的点都是偶点。另一类是只有二个奇点的图形。 2.在欧几里德提出的欧几里德算法中(即最初的欧几里德算法)用的不是除法而是减法。请用伪代码描述这个版本的欧几里德算法 1.r=m-n 2.循环直到r=0 2.1 m=n 2.2 n=r 2.3 r=m-n 3 输出m 3.设计算法求数组中相差最小的两个元素(称为最接近数)的差。要求分别给出伪代码和C ++描述。 //采用分治法 //对数组先进行快速排序 //在依次比较相邻的差 #include
int prvotkey=b[low]; b[0]=b[low]; while (low 算法初步练习题 一、选择题: 1.(09天津文)阅读下面的程序框图,则输出的S = A .14 B .20 C .30 D .55 2.(09福建)阅读图2所示的程序框图,运行相应的程序,输出的结果是 A .1 B. 2 C. 3 D. 4 3.(09福建)阅读右图所示的程序框图,运行相应的程序,输出的结果是 A .2 B .4 C .8 D .16 4.(09浙江)某程序框图如图所示,该程序运行后输出的k 的值是 A .4 B .5 C .6 D .7 5.执行右面的程序框图,输出的S 是 3题 2题 1题 4题 A .378- B .378 C .418- D .4186.如图的程序框图表示的算法的功能是 A .计算小于100的奇数的连乘积 B .计算从1开始的连续奇数的连乘积 C .从1开始的连续奇数的连乘积,当乘积大于100时,计算奇数的个数 D .计算100531≥???????n 时的最小的n 值. 7.右图是把二进制数)2(11111化为十进制数的一个程序框图,判断框内应填入的 条件是 A .4i > B .4i ≤ C .5i > D .5i ≤ 8.某程序框图如图所示,则该程序运行后输出的B 等于 A .15 B .29 C .31 D .63 5题 6题 9.(09海南)如果执行右边的程序框图,输入2,0.5x h =-=,那么输出的各个数的和等于 A .3 B .3.5 C .4 D . 10.(09辽宁)某店一个月的收入和支出总共记录了N 个数据1a ,2,,N a a ???,其中 收入记为 正数,支出记为负数。该店用右边的程序框图计算月总收入S 和月 净盈利V ,那么在图中空白的判断框和处理框中,应分别填入下列四个选项中 的 A .0,A V S T >=- B .0,A V S T <=- C .0,A V S T >=+ D .0,A V S T <=+ 11. 如图1所示,是关于闰年的流程,则 以下年份是闰年的为 A .1996年 B .1998年 C .2010年 D .2100年 11题 不使用第三个变量交换两个变量的值 通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下:int a,b; a=10; b=15; int t; t=a; a=b; b=t; 这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。 上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?这里我们可以用三种算法来实现:1)算术运算;2)指针地址操作;3)位运算。 1)算术运算 简单来说,就是通过普通的+和-运算来实现。代码如下: int a,b; a=10;b=12; a=b-a; //a=2;b=12 b=b-a; //a=2;b=10 a=b+a; //a=10;b=10 通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯标准算法之后。 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。 此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法) 2)指针地址操作 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即: int *a,*b; //假设 *a=new int(10); *b=new int(20); //&a=0x00001000h,&b=0x00001200h a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h b=(int*)(b-a); //&a=0x00000200h,&b=0x00001000h a=(int*)(b+int(a)); //&a=0x00001200h,&b=0x00001000h 通过以上运算a、b的地址真的已经完成了交换,且a指向了原先b指向的值,b指向原先a 指向的值了吗?上面的代码可以通过编译,但是执行结果却令人匪夷所思!原因何在? 首先必须了解,操作系统把内存分为几个区域:系统代码/数据区、应用程序代码/数据区、堆栈区、全局数据区等等。在编译源程序时,常量、全局变量等都放入全局数据区,局部变量、动态变量则放入堆栈区。这样当算法执行到“a=(int*)(b-a)”时,a的值并不是0x00000200h, package com.kevin.demo; /** * @author kevin.long * @description 2011-12-11 14:22:55 */ public class ChangeTest { public void changeMethodA(int a, int b){ System.out.println("changeMethodA交换之前\ta:"+a+"\tb:"+b); a = a + b - (b = a); System.out.println("changeMethodA交换之后\ta:"+a+"\tb:"+b); } public void changeMethodB(int a, int b){ System.out.println("changeMethodB交换之前\ta:"+a+"\tb:"+b); b = a + (a = b)*0; System.out.println("changeMethodB交换之后\ta:"+a+"\tb:"+b); } public void changeMethodC(int a, int b){ System.out.println("changeMethodC交换之前\ta:"+a+"\tb:"+b); a = a + b; b = a - b; a = a - b; System.out.println("changeMethodC交换之后\ta:"+a+"\tb:"+b); } public void changeMethodD(int a, int b){ System.out.println("changeMethodD交换之前\ta:"+a+"\tb:"+b); a = a * b; b = a / b; a = a / b; System.out.println("changeMethodD交换之后\ta:"+a+"\tb:"+b); } public void changeMethodE(int a, int b){ System.out.println("changeMethodE交换之前\ta:"+a+"\tb:"+b); a = a^b; b = a^b; a = a^b; System.out.println("changeMethodE交换之后\ta:"+a+"\tb:"+b); } 领航两个变量之间的关系 表示变量的三种方法:列表法、解析法(关系式法)、图象法 ◆要点1 变量、自变量、因变量 (1) 在一变化的过程中,可以取不同数值的量叫做变量,数值保持不变的量叫做常量,常量和变量往往是相对的,相对于某个变化过程。 (2) 在一变化的过程中,主动发生变化的量,称为自变量,而因变量是随着自变量的变化而发生变化的量。例如小明出去旅行,路程S、速度V、时间T三个量中,速度V一定,路程S则随着时间T的变化而变化。则T为自变量,路程为因变量。 ◆要点2 列表法与变量之间的关系 (1) 列表法是表示变量之间关系的方法之一,可表示因变量随自变量的变化而变化的情况。 (2) 从表格中获取信息,找出其中谁是自变量,谁是因变量。找自变量和因变量时,主动发生变化的是自变量,因变量随自变量的增大而增大或减小 ◆要点3 用关系式表示变量之间的关系 (1) 用来表示自变量与因变量之间关系的数学式子,叫做关系式,是表示变量之间关系的方法之一。 (2) 写变化式子,实际上根据题意,找到等量关系,列方程,但关系式的写法又不同于方程,必须将因变量单独写在等号的左边。即实质是用含自变量的代数式表示因变量。 (3) 利用关系式求因变量的值,①已知自变量与因变量的关系式,欲求因变量的值,实质就是求代数式的值; ②对于每一个确定的自变量的值,因变量都有一个确定的与之对应的值。 ◆要点4 用图象法表示变量的关系 (1) 图象是刻画变量之间关系的又一重要方式,特点是非常直观。 (2) 通常用横轴(水平方向的数轴)上的点表示自变量,用纵轴(竖直方向的数轴)上的点表示因变量。 (3) 从图象中可以获取很多信息,关键是找准图象上的点对应的横轴和纵轴上的位置,才能准确获取信息。如利用图象求两个变量的对应值,由图象得关系式,进行简单计算,从图象上变量的变化规律进行预测,判断所給图象是否满足实际情景,所给变量之间的关系等。 (4) 对比看:速度—时间、路程—时间两图象 ★若图象表示的是速度与时间之间的关系,随时间的增加即从左向 右,“上升的线段”①表示速度在增加;“水平线段”②表示速度不 变,也就是做匀速运动,“下降的线段”③表示速度在减少。 ★若图像表示的是距离与时间之间的关系,“上升的线段”①表示物 体匀速运动;“水平线段”②表示物体停止运动,“下降的线段”③ 表示物体反向运动。如图BL—01(1)、(2): 二、例题讲解 (一)列表法表示变量之间的关系 例1、果子成熟从树上落到地面,它落下的高度与经过的时间有如下的关系: (1)上表反映了哪两个变量之间的关系?哪个是自变量?哪个是因变量? (2)如果果子经过2秒落到地上,那么请估计这果子开始落下时离地面的高度是多少米? BL—01 经验技巧7-1 通用交换函数 交换两个变量的值通常是交换两个数值型变量的值,实际上,可以交换任意两个同类型对象的值,甚至是交换两个不同类型对象的值,这时需要使用内存拷贝函数memcpy来实现。 1.通用交换函数 #define SIZE 48 void TYSwap(void *vp1,void *vp2) { char buffer[SIZE]; memcpy(buffer,vp1,SIZE); memcpy(vp1,vp2,SIZE); memcpy(vp2,buffer,SIZE); } 通用交换函数TYSwap借助字符数组buffer,通过三次调用内存拷贝函数memcpy实现交换void指针vp1和vp2指向对象的存储空间的内容,从而达到交换两个对象值的目的。其中符号常量SIZE的值应为两个对象的最大存储长度。 在使用通用交换函数时,建议参加交换的两个对象的存储长度相同。 1.举例 (1)交换两个同类型对象的值 #define SIZE 8 int main() { double x=19.8,y=23.6; TYSwap(&x,&y); printf("x=%.2lf,y=%.2lf\n",x,y); return 0; } 执行结果为: x=23.6,y=19.8 实现了交换两个double型变量x和y的值。 (2)交换两个不同类型对象的值 #define SIZE 12 int main() { int a[3]={1819043144,111,0};//初始化数据对应字符串"Hello"的值char str[12]="C language"; TYSwap(a,str); printf("%s,%s\n",a,str); return 0; } 执行结果为: C language,Hello 实现了交换int型数组a和char型数组str各元素的值。 算法设计分析 答案 一、单项选择题 1-10 CCCCA ABDAA 二、判断题 1. √ 2. √ 3. √ 4. × 5. √ 6. √ 7. × 8. × 9.√10. √ 三、填空题 1.时间 2.方法过程 3.插入交换 4.数据元素 5.*n = temp 6.动态规划算法 7.高级语言编写 8.增大 9.让后面的决策安心地使用前面的局部最优解的一种性质10. 贪心选择性质 四、简答题 1. O(n2) ^2=2n,解出来n=1/50 五、问答题 1.先设置一个变量min,用于存放最小数。当输入a、b、c 三个不相同的数后,先将a 与b 进行比较,把小者送给变量min,再把 c 与min 进行比较,若c<min,则min=c。 2.算法中的每一条指令必须有确切的含义 题目 一、单项选择题(共10 题、0 / 20 分) 1、 设m[i, j] 为计算矩阵链Ai…j 所需的乘法运算次数的最小值,则矩阵链A1…n所需的乘法运算次数的最小值为()。 A、m[1,n+1] B、m[1,n-1] C、m[1,n] D、m[0,n] 收藏该题 2、二分搜索算法是基于()设计的算法。 A、穷尽法 B、分治法 C、动态规划法 D、贪心法 收藏该题 3、直接或间接的调用自身的算法称为()。 A、迭代算法 B、贪心算法 C、递归算法 D、动态规划算法 收藏该题 4、算法分析的两个主要方面是()。 A、可读性和文档性 B、正确性和简单性 C、空间复杂度和时间复杂度 收藏该题 5、下述关于最优子结构的说法,不正确的是()。 A、原问题的最优解通过子问题的非最优解合并而得 B、原问题的最优解建立在子问题的最优解基础之上 C、原问题的最优解依赖于子问题的最优解 D、原问题的最优解包含子问题的最优解 收藏该题 6、衡量一个算法好坏的标准是( )。 A、 时间复杂度低 领航两个变量之间的关系一、知识要点 表示变量的三种方法:列表法、解析法(关系式法)、图象法 ◆要点1 变量、自变量、因变量 (1) 在一变化的过程中,可以取不同数值的量叫做变量,数值保持不变的量叫做常量,常量和变量往往是相对的,相对于某个变化过程。 (2) 在一变化的过程中,主动发生变化的量,称为自变量,而因变量是随着自变量的变化而发生变化的量。例如小明出去旅行,路程S、速度V、时间T三个量中,速度V一定,路程S则随着时间T的变化而变化。则T为自变量,路程为因变量。 ◆要点2 列表法与变量之间的关系 (1) 列表法是表示变量之间关系的方法之一,可表示因变量随自变量的变化而变化的情况。 (2) 从表格中获取信息,找出其中谁是自变量,谁是因变量。找自变量和因变量时,主动发生变化的是自变量,因变量随自变量的增大而增大或减小 ◆要点3 用关系式表示变量之间的关系 (1) 用来表示自变量与因变量之间关系的数学式子,叫做关系式,是表示变量之间关系的方法之一。 (2) 写变化式子,实际上根据题意,找到等量关系,列方程,但关系式的写法又不同于方程,必须将因变量单独写在等号的左边。即实质是用含自变量的代数式表示因变量。 (3) 利用关系式求因变量的值,①已知自变量与因变量的关系式,欲求因变量的值,实质就是求代数式的值;②对于每一个确定的自变量的值,因变量都有一个确定的与之对应的值。 ◆要点4 用图象法表示变量的关系 (1) 图象是刻画变量之间关系的又一重要方式,特点是非常直观。 (2) 通常用横轴(水平方向的数轴)上的点表示自变量,用纵轴(竖直方向的数轴)上的点表示因变量。 (3) 从图象中可以获取很多信息,关键是找准图象上的点对应的横轴和纵轴上的位置,才能准确获取信息。如利用图象求两个变量的对应值,由图象得关系式,进行简单计算,从图象上变量的变化规律进行预测,判断所给图象是否满足实际情景,所给变量之间的关系等。 (4) 对比看:速度—时间、路程—时间两图象 ★若图象表示的是速度与时间之间的关系,随时间的增加即从左向 右,“上升的线段”①表示速度在增加;“水平线段”②表示速度不 变,也就是做匀速运动,“下降的线段”③表示速度在减少。 ★若图像表示的是距离与时间之间的关系,“上升的线段”①表示物 体匀速运动;“水平线段”②表示物体停止运动,“下降的线段”③ 表示物体反向运动。如图BL—01(1)、(2): 二、例题讲解 (一)列表法表示变量之间的关系 例1、果子成熟从树上落到地面,它落下的高度与经过的时间有如下的关系: (1)上表反映了哪两个变量之间的关系?哪个是自变量?哪个是因变量? (2)如果果子经过2秒落到地上,那么请估计这果子开始落下时离地面的高度是多少米? 例2、在弹性限度内,弹簧挂上物体后弹簧的长度与所挂物体的质量之间的关系如下表: 所挂物体的质量/kg 0 1 2 3 4 5 6 7 8 BL—01 例4.1 建立一个命令文件将变量a,b 的值互换,然后运行该命令文件。 程序1: 首先建立命令文件并以文件名exch.m 存盘: clear; a=1:10; b=[11,12,13,14;15,16,17,18]; c=a;a=b;b=c; a b 然后在MA TLAB 的命令窗口中输入exch ,将会执行该命令文件。 程序2: 首先建立函数文件fexch.m : function [a,b]=exch(a,b) c=a;a=b;b=c; 然后在MA TLAB 的命令窗口调用该函数文件: clear; x=1:10; y=[11,12,13,14;15,16,17,18]; [x,y]=fexch(x,y) 例4.2 求一元二次方程ax 2+bx+c=0的根。 a=input('a=?'); b=input('b=?'); c=input('c=?'); d=b*b-4*a*c; x=[(-b+sqrt(d))/(2*a),(-b-sqrt(d))/(2*a)]; disp(['x1=',num2str(x(1)),',x2=',num2str(x(2))]); 例4.3 计算分段函数: cos(1)1010x x y x ?++=?=??≠? x=input('请输入x 的值:'); if x==10 y=cos(x+1)+sqrt(x*x+1); else y=x*sqrt(x+sqrt(x)); end y 也可以用单分支if 语句来实现: x=input('请输入x 的值:'); y=cos(x+1)+sqrt(x*x+1); if x~=10 y=x*sqrt(x+sqrt(x)); end y 或用以下程序: x=input('请输入x 的值:'); if x==10 y=cos(x+1)+sqrt(x*x+1); end if x~=10 y=x*sqrt(x+sqrt(x)); end y C主讲教师崔玲玲5.1 “使用指针参数交换两个变量值”案例【案例说明】用函数实现两个变量值的交换使其在主调函数和被调函数中的值一致。要求用指针变量作为函数参数。程序运行结果如图5.1所示。图5.1 使用指针参数交换两个变量值【案例目的】1 熟悉如何定义指针变量掌握将指针变量作为函数参数的方法。2 掌握通过指针参数由被调函数向主调函数传递多个值的方法。【技术要点】由于变量的值始终存放在内存单元中因此要交换两个变量的值只需交换这两 个变量对应的存储单元的值即可这就需要知道两个变量的 地址。也就是说需要保证主调函数与被调函数中所要交换的两个数的内存单元是同一内存单元即传递的参数是内存单 元的地址而不是内存单元中的值。【相关知识及注意事项】1. 指针和地址2. 指针变量的定义及初始化3. 指针变量的赋值4. 指针变量的引用5. 指针作为函数参数5.2 “有序数列的插入”案例【案例说明】用指针法编程插入一个数到有序数列中。程序运行结果如图5.7所示。图5.7 有序数列的插入【案例目的】1 熟悉如何定义指针变量掌握将指针变量指向一维数组元素的方法。2 掌握如何在一个有序的数列中查找合适的位置。3 掌握如何将一个数插入到一个有序数列中。【技术要点】1 有序数组中插入一个数的关键是找到该数据插入的位置然后将插入位置及其后的所有元素均后移一位 在空出的位置放入待插入的数据。例如在13、27、38、49、 65、76、97这列有序数据中插入53这个数成为新的有序数列13、27、38、49、53、65、76、97。2 定义数组时必须多开辟一个存储单元用于存放待插入的数据。【相关知识及注意事项】1. 指针变量的运算2. 指针与一维数组5.3 “两个字符串首尾连接”案例【案例说明】编写程序将两个字符串首尾连接起来。要求用字符指针变量处理。程序运行结果如图5.9所示。图5.9 两个字符串首尾连接【案例目的】1 学会定义基类型为字符型的指针变量并将指针变量指向串首的操作。 2 掌握通过指针判断字符串结束的方法。 3 掌握两个字符串首尾连接的基本操作。【技术要点】1 定义指针变量p和q 将指针p指向str1串串首将指针q指向str2串串首。注意存放str1串的数组要足够大要能够存放链接后的字符串。2 通过指针p找到str1字符串串尾。3 将q所指字符串接到p所指字符串之后。 4 为p所指字符串赋串结束标志。【相关知识及注意事项】1. 定义字符指针并使其指向一个字符串2. 通过字符指针输入输出一个字符串3. 字符指针作为函数参数4. 用字符数组和字符指针处理字符串的区别5.4 “学生成绩查询”案例【案例说明】有一个班内有5个学生每个学生有4门功课的成绩。编写程序查找并输出某学生的成绩。设被查学生的序号为0l234。要求以指向数组的指针作为函数参数。程序运行结果如图5.12所示。图5.12 学生成绩查询【案例目的】1 学会定义一个指向一维数组的指针变量掌握使其算法初步练习题(附详细答案)
不使用第三个变量交换两个变量的值
不用第三个变量交换两个参数值得5种方法
两个变量之间的关系(经典和完整版)(强力推荐)
经验技巧7-1 通用交换函数
算法设计分析d卷85分
两个变量之间的关系经典和完整版
例41 建立一个命令文件将变量a,b的值互换,然后运行该命令
C语言程序设计第5章“使用指针参数交换两个变量值 ”案例