现在的位置: 首页 > 综合 > 正文

也谈冒泡排序(bubble sort)—两次‘优化’

2013年12月06日 ⁄ 综合 ⁄ 共 2620字 ⁄ 字号 评论关闭
冒泡排序(bubble sort)是最基本、最简单的排序算法,常用来作为计算机类课程算法的入门教程。闲来无事,所以重新复习一下。然后稍微闷骚的根据限界剪枝的原则做了两次优化,但是测试结果不尽如人意。
一:什么是冒泡排序(升序)
(1)依次比较array[i]和array[i+1],如果array[i]大则交换位置,结果是最大的元素到达数组末尾,像气泡一样浮上来
(2)重复上述过程,去除最后一个元素,结果是次大的元素到达数组倒数第二的位置
(3)一次类推,重复n-1次即可

算法实现如下
	public function original_b_s($array)
	{
		$count = count($array);
		$start_time = microtime(true);
		for ($i = 1; $i < $count; ++$i)
		{
			for($j = 0; $j < $count - $i; ++$j)
			{
				if($array[$j] > $array[$j + 1])
				{
					list($array[$j] , $array[$j + 1]) = array($array[$j + 1], $array[$j]) ;
				}
			}
		}
		$end_time = microtime(true);
		$message = 'eplaposed timie in '.__FUNCTION__.':'.($end_time - $start_time).'<br>';
		echo $message;
	}

二:第一次优化
我们可以想到这种极端情况:array本身就是排序好的,但是依照如上算法,我们仍然要遍历n平方/2次。原因在于,我们没有机制检查数组是否是排序好的。解决办法就是在每次冒泡过程中标记是否有相邻元素交换产生,无交换则表明排序完毕.
算法实现如下:
	public function faster_b_s($array)
	{
		$count = count($array);
		$start_time = microtime(true);
		for ($i = 1; $i < $count; ++$i)
		{
			$exchange = false;
			for($j = 0; $j < $count - $i; ++$j)
			{
				if($array[$j] > $array[$j + 1])
				{
					$exchange = true;
					list($array[$j] , $array[$j + 1]) = array($array[$j + 1], $array[$j]) ;
				}
			}
			if(!$exchange) break;
		}
		$end_time = microtime(true);
		$message = 'eplaposed timie in '.__FUNCTION__.':'.($end_time - $start_time).'<br>';
		echo $message;
	}

三:二次优化
我们再想象一种极端情况:array长度为n,但是只有第一个和第二个元素未排序,依照原始的冒泡排序仍然需要进行n-1此冒泡,其实只要一趟冒泡即可。原始的冒泡排序我们假定了第n趟冒泡的范围是0-(length-n).实际上第n趟的涉及范围取决于第n-1趟的最后交换位置,例如n-1次排序的最后交换位置是index,则表明index之后的元素都已经排序完毕,所以第n趟的涉及范围是0-index,只需要记录每一趟冒泡的最后交换位置.
算法实现如下:
	public function fatest_b_s($array)
	{
		$count = count($array);
		$start_time = microtime(true);
		$mark = $count - 1;
		for ($i = 1; $i < $count; ++$i)
		{
			for($j = 0; $j < $mark; ++$j)
			{
				if($array[$j] > $array[$j + 1])
				{
					//$exchange = true;
					list($array[$j] , $array[$j + 1]) = array($array[$j + 1], $array[$j]) ;
					$index = $j + 1;
				}
			}
			$mark = $index;
		}
		$end_time = microtime(true);
		$message = 'eplaposed timie in '.__FUNCTION__.':'.($end_time - $start_time).'<br>';
		echo $message;
	}




结语:
算法描述以及‘优化’完毕。两次优化的原则就是限界剪枝,进行更少的操作 。那么看看结果如何。
用生成的随机数填充数组,并依次调用三个排序函数,结果如下
(1)1000数组元素排序
eplaposed timie in original_b_s:0.38794994354248
eplaposed timie in faster_b_s:0.41779398918152
eplaposed timie in fatest_b_s:0.38996005058289
(2)5000数组元素排序
eplaposed timie in original_b_s:10.363991975784
eplaposed timie in faster_b_s:11.036885023117
eplaposed timie in fatest_b_s:11.047054052353
(3)10000数组元素排序
eplaposed timie in original_b_s:45.779250144958
eplaposed timie in faster_b_s:48.629040002823
eplaposed timie in fatest_b_s:48.757740974426

实验结果很失败,两次优化都耗费了更多的时间。原因是两次优化的初衷都是考虑了比较特殊的情况,想要通过减少比较次数的方法减少耗时,但是却增加了标记的耗时。
哈哈,写到这里我又做了一组测试,很有意思。主要变动就是记录了三种算法的比较次数,结果如下:
eplaposed timie in original_b_s:38.264737129211
compare count in original_b_s:49995000
eplaposed timie in faster_b_s:41.45903301239
compare count in faster_b_s:49978710
eplaposed timie in fatest_b_s:39.778419017792
compare count in fatest_b_s:49972651

实验结果表明,优化后比较次数并没有减少太多,但是增加了标记的耗时,所以导致优化后耗时更多。


抱歉!评论已关闭.