代码改变世界

不使用条件判断和比较运算符来比较大小

2012-03-08 15:23  会被淹死的鱼  阅读(3375)  评论(0编辑  收藏  举报

平时我们都是使用了比较运算符和条件判断, 来进行数字大小的比较, 但是有一些比较巧妙的方法, 也可以比较大小.

查了一些资料, 之后, 发现了三种思路, 设两个数为a和b

  1. a - b的结果, 进行移位, 取符号位, 0说明结果是正数, a > b, 1说明结果是负数, a < b
  2. (a+b)/2 + |(a-b)/2| 或者 (a+b)/2 - |(a-b)/2| , 前者可以取得较大的值, 后者取得较小的值, 很容易数学上证明
  3. 分配一个长度为a的数组array[a], 判断array[b]是否越界, 越界在java中会抛出异常

下面是用java实现的上述三种方法

第一种的代码实现

	/**
	 * 比较符号位 0表示a>b, 1表示a<b
	 * @param a
	 * @param b
	 * @return
	 */
	public static int compare(int a, int b) {
		// >> 带符号的右移, >>> 无符号的右移
//		return (((a - b) & 0x80000000) >> 31); // 判断符号位, a<b时为-1, 因为>>是带符号的右移, 保留了原来结果的符号位
		return (((a - b) & 0x80000000) >>> 31); // 判断符号位
	}

 第二种

	/**
	 * 返回a和b中较大的数
	 * @param a
	 * @param b
	 * @return
	 */
	public static int compare(int a, int b) {
		double x = (double)a;
		double y = (double)b;
		return (int)((x+y)/2 + Math.abs((x-y)/2)); // 判断符号位
	}
	
	/**
	 * 返回a和b中较小的数
	 * @param a
	 * @param b
	 * @return
	 */
	public static int compare(int a, int b) {
		double x = (double)a;
		double y = (double)b;
		return (int)((x+y)/2 - Math.abs((x-y)/2)); // 判断符号位
	}

 第三种

	/**
	 * 通过数组越界来判断
	 * @param a
	 * @param b
	 * @return
	 */
	public static int compare(int a, int b) {
		int[] array = new int[a];
		try {
			array[b] = 0; // b>a的话, 会越界, 报异常
		} catch (ArrayIndexOutOfBoundsException e) {
			return b;
		}
		return a;
	}

 三种方式的实现方法都很简单

小结

第一种可能是最差的一种, 只获得了一个谁大谁小的信息, 还需要用条件判断来返回最大最小值, 思路是好, 感觉不是特别好用.

第二种数学方法还是比较好的, 可以取得最大最小值, 而且很简单, 第三种方法很巧妙, 也可以获得最大最小值.

问题的延伸

最近看到这样一个问题

     现给有一区间: $start - $end
     给定一变量: $param
     if $param < $start 则返回$param = $start
     if $param > $end 则返回$param = $end
     不用if else, 三元 等逻辑运算符
     实现此算法

这个问题, 肯定需要不用条件和比较来比较两个数的大小,

	/**
	 * 现给有一区间: $start - $end
	 * 一变量: $param
	 * if $param < $start 则返回$param = $start
	 * if $param > $end 则返回$param = $end
	 * 不用if else, 三元 等逻辑运算符
	 * 实现此算法
	 */
	public static int compare(int param, int start, int end) {
		int[] array = new int[param];
		try {
			array[start] = 0; // param < start 越界异常
		} catch (ArrayIndexOutOfBoundsException e) {
			param = start;
		}
		
		try {
			array[end] = 0; // param > end 没有越界异常
			param = end;
		} catch (ArrayIndexOutOfBoundsException e) {
		}
		
		return param;
	}
	
	public static int compare(int param, int start, int end) {
		double p = (double) param;
		double s = (double) start;
		double e = (double) end;
		// p < s 返回较大值
		p = (p+s)/2 + Math.abs((p-s)/2);
		// p > e 返回较小值
		p = (p+e)/2 - Math.abs((p-e)/2);
		// s < p < e 返回p
		return (int)p;
	}

这种问题可能会在笔试或面试的时候遇到, 平时还是要多积累, 多思考.

由于笔者水平有限, 如果错漏, 欢迎指正!

 

参考资料:

  1. 飝兒, 不用IF比较两数大小, 原文地址: http://www.haogongju.net/art/867439