從發明新的排序算法開始扯淡(三,改進)

像這樣簡單的算法前人工程師確定想到過,即便你是初學者,若是偶然發現了這個也並不稀罕,我也沒有打算效仿郭小四竊他人成果自居,說到底這只是一篇系列扯淡文,它真正有價值的部分是由此延伸出來的問題。 html

在歸併算法中,合併兩個數列須要消耗m+n的空間,排序好了後還要將隊列拷回。在個人版本的算法中,可一開始就申請一塊等長內存,而後順次的寫入數據,而不須要寫回,一遍寫完後,交換兩塊內存,繼續寫。這樣減小了一半的寫開銷,避免了重複申請空間的問題。 算法

交換次數決定了排序完成時正確的數據寫入到了哪塊內存中。 數組

當交換次數爲偶數時,寫入原內存。 spa

當交換次數爲奇數時,寫入臨時內存。 code

若是交換次數爲奇數,那麼還要將數據拷貝至原內存。不過,在兩兩交換時,不須要額外的內存,由於比較數據只有一個,簡單交換就好了,奇數次時先進行一次比較,接下來就仍然是偶數次的了。所以在算法的主要部分前面纔有了這段代碼。 htm

int temp = len,i = 0,size = 1;
    int l1p,l1end,l2p,l2end;
    int *templist,*listb;
    printarr(list,len);
    if(len<=1){
        return;
    }
    i = 0;
    //calculate swaptimes
    while(temp){
        temp = temp>>1;
        i++;
    }
    if(i%2){
        for(i=0;(i+1)<len;i+=2){
            if(list[i]>list[i+1]){
                temp = list[i];
                list[i] = list[i+1];
                list[i+1] = temp;
            }
        }
        size = 2;
        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)的方法纔有意義。 get

之因此有這種想法,由於在位操做的世界裏,有些算法非常銷魂。

好比 

x&(x-1) 

可將X最右邊起的連續的0填充爲1

x&(-x)

可單獨抽出最右邊的1

等等。

因此老是以爲,我們的問題,也是能用O(1)解決的。

可是這些簡單好用的魔法彷佛都只和數的右側沾邊,由於操縱右邊的位數,能夠用確切知道的數,好比1 或FFFFFF,而想像操做右邊位同樣操做左邊位就不行了,除非你知道該數的log base 2 interger是什麼……若是咱們有辦法填充最左邊的0,就能得解,但這個看似很簡單的問題,竟然是個至今都無解的題,除非新版cpu出了求專門問題對應的指令,要想在低於logN的步驟內解決這個彷佛不可能了。


不過對咱們的應用來講,這還沒到頭,由於最終的目的是要知道該位是在奇數位上仍是在偶數位上。所以問題轉換爲:

把數組長度-1,若是最左邊的1落在偶數位上,則須要偶數次交換,若是落在奇數位上則須要奇數次交換

這樣一來問題彷佛很好解決了,這是改寫後的代碼

    int temp = len-1,i = 0,size = 1;
    int l1p,l1end,l2p,l2end;
    int *templist,*listb;
    printarr(list,len);
    if(len<=1){
        return;
    }
    //calculate swaptimes,only if highest bit in odd place
    if((temp&0xaaaaaaaa)<(temp&0x55555555)){
        for(i=0;(i+1)<len;i+=2){
            if(list[i]>list[i+1]){
                temp = list[i];
                list[i] = list[i+1];
                list[i+1] = temp;
            }
        }
        size = 2;
        printarr(list,len);
    }

0xAAA...AA能夠稱爲偶數柵,0x555...55能夠稱爲奇數柵,若是最高位在偶數位上,偶數 相與的結果確定大於和奇數 相與的結果的,反之亦是同理,此問題得解。
相關文章
相關標籤/搜索