从发明新的排序算法开始扯淡

开发 后端 前端 算法
像这样简单的算法前人工程师肯定想到过,即使你是初学者,如果偶然发现了这个也并不稀罕,我也没有打算效仿郭小四窃他人成果自居,说到底这只是一篇系列扯淡文,它真正有价值的部分是由此延伸出来的问题。

像这样简单的算法前人工程师肯定想到过,即使你是初学者,如果偶然发现了这个也并不稀罕,我也没有打算效仿郭小四窃他人成果自居,说到底这只是一篇系列扯淡文,它真正有价值的部分是由此延伸出来的问题。

在归并算法中,合并两个数列需要消耗m+n的空间,排序好了后还要将队列拷回。在我的版本的算法中,可一开始就申请一块等长内存,然后顺次的写入数据,而不需要写回,一遍写完后,交换两块内存,继续写。这样减少了一半的写开销,避免了重复申请空间的问题。

交换次数决定了排序完成时正确的数据写入到了哪块内存中。

当交换次数为偶数时,写入原内存。

当交换次数为奇数时,写入临时内存。

如果交换次数为奇数,那么还要将数据拷贝至原内存。不过,在两两交换时,不需要额外的内存,因为比较数据只有一个,简单交换就行了,奇数次时先进行一次比较,接下来就仍然是偶数次的了。因此在算法的主要部分前面才有了这段代码。

  1. int temp = len,i = 0,size = 1; 
  2. int l1p,l1end,l2p,l2end; 
  3. int *templist,*listb; 
  4. printarr(list,len); 
  5. if(len<=1){ 
  6.     return
  7. i = 0; 
  8. //calculate swaptimes 
  9. while(temp){ 
  10.     temp = temp>>1; 
  11.     i++; 
  12. if(i%2){ 
  13.     for(i=0;(i+1)<len;i+=2){ 
  14.         if(list[i]>list[i+1]){ 
  15.             temp = list[i]; 
  16.             list[i] = list[i+1]; 
  17.             list[i+1] = temp; 
  18.         } 
  19.     } 
  20.     size = 2; 
  21.     printarr(list,len); 

这段代码虽然完成了任务,但是有处地方特么让人不爽。就是在算交换次数的地方,用了一个O(n)的循环来获得次数。感觉有点不效率。

事实上我们只在乎长度数量的***1位在哪,因为那一位才决定交换次数。

于是开始寻找有没有更快的方法。在英文中这个问题叫Find the log base 2 of an integer,这里有一个斯坦福的页面讲这个问题 http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious

很遗憾的是,关于此问题,目前最快解也只有logN,基于二分查找法。但是把N降为logN,对于数位长度来说,真有点小题大做,仍然还是想找一个O(1)的方法才有意义。

之所以有这种想法,因为在位操作的世界里,有些算法很是销魂。

比如 

x&(x-1) 

可将X最右边起的连续的0填充为1

x&(-x)

可单独抽出最右边的1

等等。

所以总是觉得,咱们的问题,也是能用O(1)解决的。

但是这些简单好用的魔法似乎都只和数的右侧沾边,因为操纵右边的位数,可以用确切知道的数,比如1 或FFFFFF,而想像操作右边位一样操作左边位就不行了,除非你知道该数的log base 2 interger是什么……如果我们有办法填充最左边的0,就能得解,但这个看似很简单的问题,居然是个至今都无解的题,除非新版cpu出了求专门问题对应的指令,要想在低于logN的步骤内解决这个似乎不可能了。

不过对我们的应用来说,这还没到头,因为最终的目的是要知道该位是在奇数位上还是在偶数位上。因此问题转换为:

把数组长度-1,如果最左边的1落在偶数位上,则需要偶数次交换,如果落在奇数位上则需要奇数次交换

这样一来问题似乎很好解决了,这是改写后的代码

  1. int temp = len-1,i = 0,size = 1; 
  2. int l1p,l1end,l2p,l2end; 
  3. int *templist,*listb; 
  4. printarr(list,len); 
  5. if(len<=1){ 
  6.     return
  7. //calculate swaptimes,only if highest bit in odd place 
  8. if((temp&0xaaaaaaaa)<(temp&0x55555555)){ 
  9.     for(i=0;(i+1)<len;i+=2){ 
  10.         if(list[i]>list[i+1]){ 
  11.             temp = list[i]; 
  12.             list[i] = list[i+1]; 
  13.             list[i+1] = temp; 
  14.         } 
  15.     } 
  16.     size = 2; 
  17.     printarr(list,len); }

0xAAA...AA可以称为偶数栅,0x555...55可以称为奇数栅,如果***位在偶数位上,偶数 相与的结果肯定大于和奇数 相与的结果的,反之亦是同理,此问题得解。

原文链接:http://my.oschina.net/u/1167335/blog/142894

责任编辑:陈四芳 来源: oschina.net
相关推荐

2020-04-28 10:36:08

网络安全疫情技术

2022-12-26 00:00:00

排序算法洗牌算法算法

2021-07-09 09:12:40

STL排序算法

2016-07-12 10:53:07

云计算

2019-08-05 12:33:46

AI深度学习泛化

2023-10-05 09:01:05

插入排序对象序列log2i

2022-03-12 20:12:08

希尔排序数组插入排序

2015-09-01 10:21:53

排序算法总结

2009-07-08 18:28:57

惠普刀片刀片服务器

2020-10-30 10:26:21

CIO首席信息官数字化

2023-10-07 00:11:37

希尔排序算法

2023-09-26 22:22:30

选择排序Python

2022-05-17 12:23:25

排序算法面试

2011-04-20 13:56:08

选择排序

2011-04-20 14:19:00

希尔排序

2011-04-20 14:07:37

冒泡排序

2009-06-11 11:22:40

JSFJSPJSF的UI组件

2021-07-09 06:48:29

数组存储内存
点赞
收藏

51CTO技术栈公众号