日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

位运算与组合搜索(二)

發(fā)布時間:2025/6/15 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 位运算与组合搜索(二) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

People who play with bits should expect to get bitten.

-- Jurg Nievergelt

I failed math twice, never fully grasping probability theory.

I mean, first off, who cares if you pick a black ball or a white ball out of the bag?

And second if you’re bent over about the color, don’t leave it to chance.

Look in the damn bag and pick the color you want.

-- Stephanie Plum

這篇文章接著講怎樣高效地遍歷所有的組合。同樣,假定全集的大小不大于機器字長,計算模型為 word-RAM,即諸如 +, –, *, /, %, &, |, >>, << 等此類操作皆可以在 O(1) 時間內(nèi)完成。當然,一般 / 和 % 操作明顯要慢上一些,因此我們總是希望能夠盡量避免使用兩個操作。在上一篇 blog 中的子集遍歷比較簡單,基本上只用到了 +, – , & 三種操作。而組合遍歷相對要復(fù)雜得多,一些讓人不舒服的操作總是難以避免。下面將要介紹兩種完全不同的組合遍歷算法,其中一種用到了 / 操作,而另一種則使用了三目運算符。盡管不算十分完美,也應(yīng)該是足夠高效啦。


2 遍歷所有組合

2.1 colex & reverse colex

說到各種位運算技巧,早年從 MIT 流傳出來的一份技術(shù)報告 HAKMEM 可謂是一本黑暗圣經(jīng)。在 HAKMEM 的第175條中記錄著一個非常巧妙而實用的技巧,被稱為 Gosper’s hack,它僅僅使用幾個非常簡單的算術(shù)運算和位運算,即可得到與當前所輸入的整數(shù)含有相同數(shù)目的1的下一個整數(shù):

s = x & (-x);

r = s + x;

n = r | (((x ^ r) >> 2) / s);

在上面這段代碼中 x 是輸入,n 是輸出,為大于 x 且與 x 含1個數(shù)相同的最小整數(shù)。比如若輸入 x = 0b0101, 那么將輸出 n = 0b0110。使用這一技巧使得我們可以非常容易地生成所有組合,代碼如下:(這是一個成員函數(shù),完整的代碼可在位運算與組合搜索(一)所附的壓縮包中找到):

bool next(unsigned long &x) const {if (x == last_) return false;unsigned long r, s;s = x & (-(long)x);r = s + x;x = r | (((x ^ r) >> 2) / s);return true; }

上面代碼中的 last_ 表示的是最后一個組合。這里遍歷組合的序為 colex,最小的組合是所有1都在低位,而最大的組合(即 last_) 是當所有1都在高位。比如若全集為 {a, b, c, d, e},我們用以上代碼遍歷其所有大小為2的子集,順序?qū)⑷缦卤硭?#xff1a;

序號位串子集
10b0001111000{a, b}
20b0010110100{a, c}
30b0011001100{b, c}
40b0100110010{a, d}
50b0101001010{b, d}
60b0110000110{c, d}
70b1000110001{a, e}
80b1001001001{b, e}
90b1010000101{c, e}
100b1100000011{d, e}

現(xiàn)在稍微來解釋 Gosper’ hack 是怎樣工作的:

第一條語句:s = x & (-x), 用于標識出 x 最低位的1(設(shè)最低的1右邊有 c 個0)。 e.g. 0b10110 –> 0b00010

第二條語句:r = s + x, 將 x 右端的連續(xù)一段1清零(紅色標識的部分,設(shè)這一段有 k 個1),并將前一位設(shè)為1。 e.g. 0b10110 –> 0b11000

第三條語句:n = r | (((x ^ r) >> 2) / s), 這里先用 x 異或 r 得到 k + 1 + c 個連續(xù)的1。然后右移 2 位,再除于 s (相當于右移 c 位),得到 k – 1 位連續(xù)的1,最后添加到 r 的最右邊,打完收工。e.g. 0b11000 | 0b00001 = 0b11001

由于該 hack 中的除法實際上只是用來移位的,因此可以想辦法繞過去 (如果你實在看不順眼那個除號的話)。比如可以使用 bsr 指令計算出 c ,然后直接移位即可。但經(jīng)過我的測試,發(fā)現(xiàn)還是直接除法來得比較快。

// Find last bit set static inline unsigned long __fls(unsigned long x) {__asm bsr eax, x; }

現(xiàn)在如果想要反向生成所有的組合那又該如何呢,其實很簡單,因為 colex 具有一種某種意義上的對稱性:某個組合的前一個組合等于這個組合的補集的下一個組合的補集。如果我們想要得到組合 x 按照 colex 的上一個組合,只需生成 ~x 的下一個組合,再取反即可:

bool prev(unsigned long &x) const {if (x == first_) return false;x = ~x;next(x);x = ~x;return true; }

2.2 cool-lex & reverse cool-lex

cool-lex,顧名思義,就是非常 cool 的 lex。cool-lex 是由 Frank Ruskey 和 Aaron Williams 發(fā)明的,如果想要詳細的了解 cool-lex 的性質(zhì),可以看一下參考文獻6。另外在這里還有一段 cool-lex 的音樂,感興趣的可以試聽一下。雖然它不怎么好聽,也顯然不可能給你帶來關(guān)于 cool-lex 的任何洞見。下面我只簡單介紹一下怎樣按照 cool-lex 或者反向 cool-lex 進行組合遍歷。

cool-lex 的生成算法是基于后綴旋轉(zhuǎn)的(如果是針對位串表示則是前綴旋轉(zhuǎn),但下面我們都是針對二進制整數(shù)表示,也就是低位在右邊):找到最短的以010或者110開始的后綴(如果不存在則選定全部位),然后向左旋轉(zhuǎn)1位。比如組合0b01101,? 首先找出最短的以010或者110開始的后綴(用紅色表示):0b01101,然后將這個后綴向左旋轉(zhuǎn)1位(即循環(huán)左移1位)即得到下一個組合:0b01011

如何借助于位運算高效的完成后綴旋轉(zhuǎn)呢,Donald 在 TAoCP 中7.2.1.3節(jié)習題55的答案中給出了一個 MMIX 實現(xiàn)。下面的代碼是我寫的一個C++版:

bool next(unsigned long &x) const {if (x == last_) return false;unsigned long r, s;r = x & (x + 1);s = r ^ (r - 1);r = ((s + 1) & x) ? s : 0;x = x + (x & s) - r;return true; }

上面代碼中的 last_ 當然也是指最后一個組合。cool-lex 中的第一個組合也是所有1在低位,即類似于這樣:0b0…01…1。最后一個組合是1個1在最高位,而其余的1在低位,即形如 0b10…01…1。這段代碼到底是怎么起作用的?你猜!我就不分析了,不過我等下會詳細解釋生成 reverse cool-lex 的代碼。下表是 cool-lex 序的一個例子(同樣,全集為 {a, b, c, d, e},子集大小為 2):

序號位串子集
10b0001111000{a, b}
20b0011001100{b, c}
30b0010110100{a, c}
40b0101001010{b, d}
50b0110000110{c, d}
60b0100110010{a, d}
70b1001001001{b, e}
80b1010000101{c, e}
90b1100000011{d, e}
100b1000110001{a, e}

現(xiàn)在來講怎樣反向遍歷 cool-lex。reverse cool-lex 被提到的不多,網(wǎng)上以及各種文獻上也并沒有生成 reverse cool-lex 的代碼,因此我只好自己寫了一個。想要得到高效的 cool-lex 反向遍歷代碼,首先需要一個簡單的生成規(guī)則。這個規(guī)則其實根據(jù)正向 cool-lex 的規(guī)則可以很容易地yy出來:找到最短的以100或者101開始的后綴(如果不存在則選定全部位),然后向右旋轉(zhuǎn)1位。(后來我向 Frank 請教了一下,他說這個規(guī)則的確是正確的,另外還告訴我 Aaron 的另一篇文章 “l(fā)oopless generation of multiset permutations by prefix shifts” 對 reverse cool-lex 作了介紹。)

規(guī)則有了,還剩下最后一個問題,那就是怎樣借助于位運算高效的實現(xiàn)這個規(guī)則。下面是我的實現(xiàn):

bool prev(unsigned long &x) const {if (x == first_) return false;unsigned long r, s, v;v = x | 1;r = v & (v + 1);s = r ^ (r - 1);v = s & x;r = (v & 1) ? s - (s >> 1) : 0;x = x & (~s) | r | (v >> 1);return true; }

上面的代碼中,基本上都是非常基礎(chǔ)的位運算技巧,如果你對此并不熟悉,不妨看一下參考文獻1或3。首先,我們需要找到最短的以 100 或者 101 開始的后綴,這將通過下面四條語句來完成:

第一條語句:v = x | 1,將最低位置1。e.g. 0b01010 –> 0b01011

第二條語句:r = v & (v + 1),清除右邊連續(xù)的1。 e.g. 0b01011 –> 0b01000

第三條語句:s = r ^ (r – 1),標記最低位的1以及其后的0。e.g. 0b01000 –> 0b01111

第四條語句:v = s & x,得到后綴。e.g. 0b01111 & 0b01010 –> 0b01010

至此,滿足條件的后綴已經(jīng)找出來了,下一步的工作就是將它右旋一位:

第五條語句:r = (v & 1) ? s - (s >> 1) : 0, 得到旋轉(zhuǎn)后的后綴的最高位。 e.g. 0b01111 - 0b00111 –> 0b01000

第六條語句:x = x & (~s) | r | (v >> 1),將后綴右移一位,與最高位相或,再與其余不相干的位合并,即得到最終結(jié)果。 e.g. 0b00101

在第五條語句用到了三目運算符,這里其實也可以借助 bsr 指令繞過去。我并沒有比較哪種更快一些。

完。(做人要厚道,轉(zhuǎn)載請注明出處:http://www.cnblogs.com/atyuwen/)


3 參考文獻

  • Henry S. W., Hacker’s Delight.
  • J?rg A., Matters Computational.
  • Donald E. K., The Art of Computer Programming: Bitwise Tricks and Techniques. Volume 4, Pre-Fascicle 1A.
  • Donald E. K., The Art of Computer Programming: Generating all Combinations and Partitions. Volume 4, Fascicle 3.
  • Beeler M., Gosper R. W., and Schroeppel R., HAKMEM
  • Frank R., Aaron W., The Coolest Way To Generate Combinations.
  • P.S. 對于我這種從小就怕寫作文的人來說,寫篇稍正式一點的技術(shù)文章實在是太辛苦了,因此關(guān)于位運算與組合搜索就先寫到這里,雖然有很多想說的還沒有談到。以后有心情了再來討論怎樣高效實現(xiàn)(一)中提到的映射操作及其逆操作。

    轉(zhuǎn)載于:https://www.cnblogs.com/atyuwen/archive/2010/08/05/bit_comb_2.html

    《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的位运算与组合搜索(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 91二区| 91精品国产色综合久久不卡98口 | 国产精品黄在线观看 | 在线视频观看 | 久久久久久亚洲av毛片大全 | 色精品视频 | 哪里可以免费看av | 亚洲色图17p | 超碰人人在线 | 人人干人人搞 | 成人午夜sm精品久久久久久久 | 国产区一区二区三区 | 人人澡澡人人 | 99久久人妻无码中文字幕系列 | 最新av中文字幕 | 亚洲丁香网 | 我把护士日出水了视频90分钟 | 国产精品日韩在线观看 | 日本免费专区 | 91精品国产乱码久久久久久久久 | 久热这里只有 | 成人国产精品免费观看视频 | 日本欧美一区二区三区不卡视频 | 亚洲欧美日韩专区 | 欧美乱妇高清无乱码 | 欧美三级影院 | 人妻精品久久久久中文字幕 | 一级黄色在线播放 | 国产欧美日韩专区 | 日韩五码在线 | 亚洲国产精品女人久久久 | 欧美做爰全过程免费观看 | 欧美另类色图 | 黄色一集片| 亚洲乱码国产乱码精品精剪 | 自拍第二页 | 小黄网站在线观看 | av丝袜天堂| 欧美性视频网站 | 偷拍视频久久 | 亚洲 小说区 图片区 都市 | 91极品蜜桃臀 | 91成人在线免费观看 | 老熟妇精品一区二区三区 | jizzjizz黄大片| 成人视品 | 张津瑜国内精品www在线 | av老司机在线观看 | 9.1在线观看免费 | 一区二区亚洲精品 | 国产色秀| 精彩视频一区二区 | 夜夜夜久久久 | 5d肉蒲团之性战奶水 | 东北少妇露脸无套对白 | 毛片无码一区二区三区a片视频 | 影音先锋成人资源网 | 97久久精品视频 | 精品啪啪 | 免费的一级黄色片 | 日本一二三区在线视频 | 天天操天天爽天天干 | 中国毛片视频 | 丰满岳乱妇国产精品一区 | 日韩乱码人妻无码中文字幕 | 免费成人深夜夜国外 | 欧美午夜久久 | 久久久久久久久久影视 | 少妇日韩| 麻豆视频免费网站 | 夏目彩春娇喘呻吟高潮迭起 | 暗呦丨小u女国产精品 | 日韩欧美中文在线 | 小视频在线播放 | 超碰在线99 | 亚洲无限看 | 国产精品美女一区二区 | 色呦呦视频 | 国产日本精品 | 免费观看的毛片 | 日日摸日日碰 | 日韩福利| 成人一区在线观看 | 国产精品久久一区二区三区 | 亚洲网站在线看 | 日韩人妻精品一区二区三区视频 | 日本aa大片 | 日韩中文免费 | 蜜桃av在线 | 桃色成人 | 丁香五香天堂 | av网站免费在线 | 韩日欧美 | 91成人国产| 窝窝午夜视频 | 蜜臀av粉嫩av懂色av | 一本久道在线 | 麻豆传媒视频入口 | 日韩av导航 |