直击信息本质 - 快速排序

7 篇文章 0 订阅
5 篇文章 0 订阅

                                  用排序来直击信息的本质

前言:

         快速排序作为应用场景最丰富的排序算法之一,是社会科学中的非常基础算法之一,作为冒泡排序的改进版本,改进方向,实质是对信息的利用率改进

 

算法原理:

     1.快速排序的原理选取一个元素,切割数据为两份,其中一份放全部大于这个元素的数据,另一个放全部小于他的数据,

     2.然后对切割后的两份数据(两份数据都不包含当前选取的元素)做步骤1的操作,直至数据长度为1时停止。

     3.无数据可以操作,完成排序。

     以上面代码为例 :

      1.先选取一组数据中的一个元素,然后把大于这个元素的放到一侧,小于这个元素的放到另外一侧。(在上面的代码中,选取的总是数据中的最后一个)

      2.然后对两侧的数据分别视为一组数据执行步骤1,进行递归逻辑。(当一组数据长度小于等于1时不在进行递归逻辑)

      3.无数据可在进行递归,排序完成。

      ps:相信大家小时候上体育课一定遇到过从大到小从高到矮的排队问题,经常能碰到老师排半个小时,使用快速排序的思想能快速排好。先让同学们站成一排,以最左边的同学为参照物,高于他的站左边,低于他的站右边,整体居中,以他为分界变成两个队伍向前走一步,此同学不动,然后让每个队伍在执行上面的逻辑,让队伍的变成一人大小时停止,最后所有人退后到最开始并排线,就完成了这个排队操作。

 

设:

     下列代码,其中arr为数组,len为数组长度,quickSort为排序入口函数。

伪码:

  quickSort(array,len)
  {
	quickSortRecursion(0,len-1,array)
  }  

  

  quickSortRecursion(start,end,array)
  {
		if(end<start)
		{
			return;
		}
		key= array[end];
		index = start-1;
		for(i=start;i<=end-1;i++)
		{

			if(array[i]<key)
			{
				index++;
				exchange(index,i);
			}
		}
		index++;
		exchange(index,end);
		quickSortRecursion(start,index-1);
		quickSortRecursion(index+1,end);
			
   }
		
   exchange(a,b,array)
   {
         v = array[a];
         array[a] = array[b];
         array[b] = v;
   }

算法动图:

 

算法性能:

    (1)最佳性能:

       1.按上面的算法可以得到每一组数据,拆分成两组数据,那么历次外循环的份数结果就是1,2,4,8....len,很明显可以得到外循环的最小次数为log2(len)。(以2为底,len的对数,在这里说明下为什么最少的循环次数一定是log2(len),那是因为,如果不是平均分割,其中一侧的A数据大于另一侧数据B,那么这个A继续除以2直至变成1的次数肯定会要变多。举个极端例子例如每次A分割完毕后的长度都等于len-1,B的长度等于1,那么A需要len-1次之后长度才能变成1,而如果是均匀分割的话A最多只需要log2(len)次后长度变成1。带入实际数字,len=8,那么不均匀分割A的长度要等于1需要len-1=7次,那么均匀分割只需要log2(len)=3次)

       2.设log2(len)=M。

      3.每一次外循环需要处理的数据量为 len- (2^i-1)。

      4.求和∑len- (2^i-1) 。 (i从0到M)

      5.对(2^i-1) 求和可以得知(2^i-1)  = 2^(M+1)-1 -M  = 2*len-M -1 。(从三个式可以得出化简过程,公式:2^(M+1)=2*2^M,公式:2^M=len,公式:2^0+2^1+2^2+....2^k =  2^(k+1)-1)

      6.其中len部分求和为len*M。

      7.最终的公式合并为len*M-(2*len-M-1)= len*(M-2+M/len+1/len),其中M/len和1/len是一个远远小于1的数字,可以忽略不计,根据性能计算规则舍弃常数项就可以得到M-2=M,所以其算法性能为len*M即时间复杂度为O(n*log2(n))。

 

      (2)最差性能:

        1.在实际情况中可能发生,每次分割只能得到一个数组,每次外循环完毕后,其余的元素都是在选中元素的同一侧。那么这个时候算法,每一次就只能剔除一个元素,其性能就是len+len-1+len-2+len-3+....+1+0。根据等差数列求和公式可以得到(0+len)*len/2=len²/2即时间复杂度为O(n²)。

      (3)综合性能:

       那么在这里得到最差和最坏性能一个是n² 一个是n log2(n),因为最差性能需要有序序列等特殊情况才会出现,在总的数据排列组合样本中属于小概率事件,而一般数据样本情况都是接近最佳性能,所以快速排序的性能为n log2(n)。

 

结语:

       1.冒泡排序和快速排序最本质的上的区别在于,冒泡排序在进行元素比较时(比较两个元素的大小),比较结果的利用率只有百分之五十(例如从小到大排序,当arr[i]>arr[i+1],为真的时候才会交换元素位置,在另外一种情况的时候什么都不做)

        2.事实上快速排序是选取一固定元素,与其余元素进行比较,当小于就放到一侧,大于就放到另一侧。在这里充分利用了一个布尔运算可能产生的两个结果,即真假两个结果。

         3.快速排序比冒泡排序快,是因为改进了信息的利用率。

         4.在快速排序中使用了假设的逻辑,假定了选取的元素恰好是中位数(大小刚好处于中间,恰好能把数据分割成两个一样长度的数据),事实上很有可能左侧或者右侧,一个元素都不存在。这种情况恰好在实际应用中非常容易出现,例如一组数据已经是已有循序序列(已经从小到大排序好了),这个时候快速排序会退化成冒泡排序,性能甚至比冒泡排序更慢。(虽然指数方面快速排序最差情况和冒泡排序最差情况一致,但是快速排序需要更高的系数开销)

         5.选择固定位置的元素来进行快速排序可能会遇到最差性能。解决这个问题,可以在选取元素时使用随机选取(上面代码中选取的总是数据的最后一个元素),可以有效降低遇到最差性能的概率,但是不管怎么做,这个情况是无非完全避免的。(假设条件可能不生效,导致遇到最差性能)(选取元素时可以采用启发式算法来进行更好的进行数据选取。单纯的随机在某种程度上来说就是简单的启发式算法,也是能适用的,那么也就是说解决快速排序的这个问题上在进行深入,可以采用类似于"人工智能"的解决方案来解决这个问题,因为启发式算法可以看做简单版的"人工智能"解决方案。训练数据模型,得出数据特征,获取特征函数,创建映射函数,当然这是比较深度的优化方式了,不过多的讨论,这里引出只是为了联系各个学科,揭开相关技术的神秘面纱,揭示问题的本质)

         6.只有最适用的算法,并不存在最好的算法

         7.在某些情况下一个基础算法可能达到的性能更高(在特例情况下,冒泡排序比快速排序快),然而这些情况基本都是能得到的信息(在项目一定会有许多的已知确定条件)如何高效的利用信息,是优化算法与逻辑的关键

 

最后:

          1.可以假定一些条件来提升算法的性能。(假定每次选中的数据恰好是中位数)

          2.假定的条件可能会失效,它会让算法的优化失败,让优化算法退化成基本算法,导致性能比优化前更低下。如果要优化一个逻辑或者算法,需要具体问题分析,避免算法陷入退化的状态,这是程序与逻辑优化的关键,盲目的优化往往会得不偿失(快速排序就退化成了冒泡排序)

           3.没有最好的算法,只有最适合的算法。(某些时候优化过后的算法,甚至比没有优化的算法更差,快速排序在处理有序序列时比冒泡排序性能要差)

 

ps:

      1.由于快速排序的特性(分治算法),实际上是能使用多线程运算加快排序速度。 

      2.在实际项目中会有很多的逻辑跳转,往往只使用了其中的一种情况,另外一种情况并没有做处理,或者需要处理的时候又重新进行了计算,这里就是很多逻辑漏洞的来源,是性能丧失的来源,所以碰到逻辑跳转时,如果如果其中一个分支执行逻辑为空时,需要重新审视自己的逻辑是否设计合理,是否有漏洞,如果能有这个意识,将会有质的提升。(实际上在设计足够出色的时候逻辑跳转是极少的,逻辑跳转往往代表的就是特殊化处理,逻辑跳转越少代表问题抽象程度越高,逻辑质量也越高,当然这就是另外一个话题了)

      3.最后附上冒泡排序

   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值