• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            面對(duì)現(xiàn)實(shí),超越自己
            逆水行舟,不進(jìn)則退
            posts - 269,comments - 32,trackbacks - 0

             近期在工作中發(fā)現(xiàn),許多同事,尤其是我們的PHP開發(fā)者,基本不會(huì)用Linux/unix下的快捷方式,嚴(yán)重影響工作效率,所以特撰寫此文,每個(gè)用法后我會(huì)詳細(xì)注釋。

              下述所有命令在Linux/unix的shell下有效,這里以bash為主。如有出入,以你自己的服務(wù)器為準(zhǔn)。本文所指的Linux主要指RHEL/CentOS,unix指的是FreeBSD,這也是服務(wù)器中用得最多的版本。

              Ctrl + a 切換到命令行開始

              這個(gè)操作跟Home實(shí)現(xiàn)的結(jié)果一樣的,但Home在某些unix環(huán)境下無法使用,便可以使用這個(gè)組合;在Linux下的vim,這個(gè)也是有效的;另外,在windows的許多文件編輯器里,這個(gè)也是有效的。

              Ctrl + e 切換到命令行末尾

              這個(gè)操作跟END實(shí)現(xiàn)的結(jié)果一樣的,但End鍵在某些unix環(huán)境下無法使用,便可以使用這個(gè)組合;在Linux下的vim,這個(gè)也是有效的;另外,在windows的許多文件編輯器里,這個(gè)也是有效的。

              Ctrl + l 清除屏幕內(nèi)容,效果等同于clear

              Ctrl + u 清除剪切光標(biāo)之前的內(nèi)容

              這個(gè)命令很有用,在nslookup里也是有效的。我有時(shí)看見同事一個(gè)字一個(gè)字的刪除shell命令,十分崩潰!其實(shí)完全可以用一個(gè)Ctrl + u搞定。

              Ctrl + k 剪切清除光標(biāo)之后的內(nèi)容

              Ctrl + y 粘貼剛才所刪除的字符

              此命令比較強(qiáng)悍,刪除的字符有可能是幾個(gè)字符串,但極有可能是一行命令。

              Ctrl + r 在歷史命令中查找 (這個(gè)非常好用,輸入關(guān)鍵字就調(diào)出以前的命令了)

              這個(gè)命令我強(qiáng)烈推薦,有時(shí)history比較多時(shí),想找一個(gè)比較復(fù)雜的,直接在這里,shell會(huì)自動(dòng)查找并調(diào)用,方便極了

              Ctrl + c 終止命令

              Ctrl + d 退出shell,logout

              Ctrl + z 轉(zhuǎn)入后臺(tái)運(yùn)行

              不過,由Ctrl + z轉(zhuǎn)入后臺(tái)運(yùn)行的進(jìn)程在當(dāng)前用戶退出后就會(huì)終止,所以用這個(gè)不如用nohup命令&,因?yàn)閚ohup命令的作用就是用戶退出之后進(jìn)程仍然繼續(xù)運(yùn)行,而現(xiàn)在許多腳本和命令都要求在root退出時(shí)仍然有效。

              下面再被充下大家不是太熟悉,我用得比較多的操作方式:

              !!  重復(fù)執(zhí)行最后一條命令

              history 顯示你所有執(zhí)行過的編號(hào)+歷史命令。這個(gè)可以配合!編輯來執(zhí)行某某命令

              ↑(Ctrl+p) 顯示上一條命令

              ↓(Ctrl+n) 顯示下一條命令

              !$ 顯示系統(tǒng)最近的一條參數(shù)

              最后這個(gè)比較有用,比如我先用cat /etc/sysconfig/network-scripts/ifconfig-eth0,然后我想用vim編輯。一般的做法是先用↑ 顯示最后一條命令,然后用Home移動(dòng)到命令最前,刪除cat,然后再輸入vim命令。其實(shí)完全可以用vim !$來代替。

              開發(fā)和管理員的話,掌握以上用法后,基本上工作就很有效率了;用到最后,你會(huì)不經(jīng)意發(fā)現(xiàn),彈指之間,許多復(fù)雜的指令你會(huì)很輕松的搞定。

              附錄:Linux下的桌面環(huán)境的快捷方式

              以下指令在Linux/unix的桌面環(huán)境(gnome)下有效,如有出入以你自己的服務(wù)器為準(zhǔn):

              Alt + F1 類似Windows下的Win鍵,在GNOME中打開"應(yīng)用程序"菜單(Applications)

              Alt + F2 類似Windows下的Win + R組合鍵,在GNOME中運(yùn)行應(yīng)用程序

              Ctrl + Alt + D 類似Windows下的Win + D組合鍵,顯示桌面

              Ctrl + Alt + L 鎖定桌面并啟動(dòng)屏幕保護(hù)程序

              Alt + Tab 同Windows下的Alt + Tab組合鍵,在不同程序窗口間切換

              PrintScreen 全屏抓圖

              Alt + PrintScreen 當(dāng)前窗口抓圖

              Ctrl + Alt + → / ← 在不同工作臺(tái)間切換

              Ctrl + Alt + Shift + → / ← 移動(dòng)當(dāng)前窗口到不同工作臺(tái)

              Ctrl+Alt+Shift+Fn 終端N或模擬終端N(n和N為數(shù)字1-6)

              Ctrl+Alt+Shift+F7 返回桌面

              Ctrl+Alt+Shift+F8 未知(終端或模擬終端)

              窗口操作快捷鍵

              Alt + F4 關(guān)閉窗口

              Alt + F5 取消最大化窗口 (恢復(fù)窗口原來的大小)

              Alt + F7 移動(dòng)窗口 (注: 在窗口最大化的狀態(tài)下無效)

              Alt + F8 改變窗口大小 (注: 在窗口最大化的狀態(tài)下無效)

              Alt + F9 最小化窗口

              Alt + F10 最大化窗口

              Alt + Space 打開窗口的控制菜單 (點(diǎn)擊窗口左上角圖標(biāo)出現(xiàn)的菜單)

              應(yīng)用程序中的常用快捷鍵

              下面這些并不適用于所有程序。可以和Windows下的快捷鍵類比下:

              Ctrl+N 新建窗口

              Ctrl+X 剪切

              Ctrl+C 復(fù)制

              Ctrl+V 粘貼

              Ctrl+Z 撤銷上一步操作

              Ctrl+Shift+Z 重做剛撤銷的一步操作

              Ctrl+S 保存

              文件瀏覽器

              Ctrl+H 顯示隱藏文件(切換鍵)

              Ctrl+T 新建標(biāo)簽

              Ctrl+Page Up 上一個(gè)標(biāo)簽

              Ctrl+Page Down 下一個(gè)標(biāo)簽

              Alt+N 切換到第N個(gè)標(biāo)簽(N為數(shù)字)

                  打開終端的方式:

                  1.鼠標(biāo)點(diǎn)右鍵--terminal,即可打開。

                  2.點(diǎn)任務(wù)欄的“application”里面的“terminal”打開

                  3.命令方式:Alt+F2后在出現(xiàn)"運(yùn)行應(yīng)用程序"中輸入x-terminal-emulator(一般在你輸入到x-term后系統(tǒng)會(huì)自己顯示全部)或者輸入“gnome-terminal“


            本為轉(zhuǎn)自:http://linux.chinaitlab.com/command/815732.html

            posted @ 2013-02-25 09:57 王海光 閱讀(1314) | 評(píng)論 (0)編輯 收藏

               不管實(shí)在C還是C++代碼中,typedef這個(gè)詞都不少見,當(dāng)然出現(xiàn)頻率較高的還是在C代碼中。typedef與#define有些相似,但更多的是不同,特別是在一些復(fù)雜的用法上,就完全不同了,看了網(wǎng)上一些C/C++的學(xué)習(xí)者的博客,其中有一篇關(guān)于typedef的總結(jié)還是很不錯(cuò),由于總結(jié)的很好,我就不加修改的引用過來了,以下是引用的內(nèi)容(紅色部分是我自己寫的內(nèi)容)。

            用途一:

            定義一種類型的別名,而不只是簡(jiǎn)單的宏替換。可以用作同時(shí)聲明指針型的多個(gè)對(duì)象。比如:

            char* pa, pb; // 這多數(shù)不符合我們的意圖,它只聲明了一個(gè)指向字符變量的指針,

            // 和一個(gè)字符變量;

            以下則可行:

            typedef char* PCHAR;

            PCHAR pa, pb;  

            這種用法很有用,特別是char* pa, pb的定義,初學(xué)者往往認(rèn)為是定義了兩個(gè)字符型指針,其實(shí)不是,而用typedef char* PCHAR就不會(huì)出現(xiàn)這樣的問題,減少了錯(cuò)誤的發(fā)生。

            用途二:
            用在舊的C代碼中,幫助struct。以前的代碼中,聲明struct新對(duì)象時(shí),必須要帶上struct,即形式為: struct 結(jié)構(gòu)名對(duì)象名,如:

            struct tagPOINT1

             {
                int x;

                int y; 
            };

            struct tagPOINT1 p1;

            而在C++中,則可以直接寫:結(jié)構(gòu)名對(duì)象名,即:tagPOINT1 p1;

            typedef struct tagPOINT
            {
                int x;

                int y;
            }POINT;

            POINT p1; // 這樣就比原來的方式少寫了一個(gè)struct,比較省事,尤其在大量使用的時(shí)

            候,或許,在C++中,typedef的這種用途二不是很大,但是理解了它,對(duì)掌握以前的舊代

            碼還是有幫助的,畢竟我們?cè)陧?xiàng)目中有可能會(huì)遇到較早些年代遺留下來的代碼。

            用途三:

            用typedef來定義與平臺(tái)無關(guān)的類型。

            比如定義一個(gè)叫 REAL 的浮點(diǎn)類型,在目標(biāo)平臺(tái)一上,讓它表示最高精度的類型為:

            typedef long double REAL;

            在不支持 long double 的平臺(tái)二上,改為:

            typedef double REAL;

            在連 double 都不支持的平臺(tái)三上,改為:

            typedef float REAL;

            也就是說,當(dāng)跨平臺(tái)時(shí),只要改下 typedef 本身就行,不用對(duì)其他源碼做任何修改。

            標(biāo)準(zhǔn)庫(kù)就廣泛使用了這個(gè)技巧,比如size_t。另外,因?yàn)閠ypedef是定義了一種類型的新別名,不是簡(jiǎn)單的字符串替換,所以它比宏來得穩(wěn)健。
                 這個(gè)優(yōu)點(diǎn)在我們寫代碼的過程中可以減少不少代碼量哦!

            用途四:

            為復(fù)雜的聲明定義一個(gè)新的簡(jiǎn)單的別名。方法是:在原來的聲明里逐步用別名替換一部

            分復(fù)雜聲明,如此循環(huán),把帶變量名的部分留到最后替換,得到的就是原聲明的最簡(jiǎn)化

            版。舉例: 

             原聲明:void (*b[10]) (void (*)());

            變量名為b,先替換右邊部分括號(hào)里的,pFunParam為別名一:

            typedef void (*pFunParam)();

            再替換左邊的變量b,pFunx為別名二:

            typedef void (*pFunx)(pFunParam);

            原聲明的最簡(jiǎn)化版:

            pFunx b[10];
             
            原聲明:doube(*)() (*e)[9];

            變量名為e,先替換左邊部分,pFuny為別名一:

            typedef double(*pFuny)();

            再替換右邊的變量e,pFunParamy為別名二

            typedef pFuny (*pFunParamy)[9];

            原聲明的最簡(jiǎn)化版:

            pFunParamy e;

            理解復(fù)雜聲明可用的“右左法則”:從變量名看起,先往右,再往左,碰到一個(gè)圓括號(hào)

            就調(diào)轉(zhuǎn)閱讀的方向;括號(hào)內(nèi)分析完就跳出括號(hào),還是按先右后左的順序,如此循環(huán),直

            到整個(gè)聲明分析完。舉例:

            int (*func)(int *p);

            首先找到變量名func,外面有一對(duì)圓括號(hào),而且左邊是一個(gè)*號(hào),這說明func是一個(gè)指針

            ;然后跳出這個(gè)圓括號(hào),先看右邊,又遇到圓括號(hào),這說明(*func)是一個(gè)函數(shù),所以

            func是一個(gè)指向這類函數(shù)的指針,即函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值

            類型是int。

            int (*func[5])(int *);

            func右邊是一個(gè)[]運(yùn)算符,說明func是具有5個(gè)元素的數(shù)組;func的左邊有一個(gè)*,說明

            func的元素是指針(注意這里的*不是修飾func,而是修飾func[5]的,原因是[]運(yùn)算符

            優(yōu)先級(jí)比*高,func先跟[]結(jié)合)。跳出這個(gè)括號(hào),看右邊,又遇到圓括號(hào),說明func數(shù)

            組的元素是函數(shù)類型的指針,它指向的函數(shù)具有int*類型的形參,返回值類型為int。

            這種用法是比較復(fù)雜的,出現(xiàn)的頻率也不少,往往在看到這樣的用法卻不能理解,相信以上的解釋能有所幫助。

            *****以上為參考部分,以下為本人領(lǐng)悟部分*****

            使用示例:

            1.比較一:

            #include <iostream>

            using namespace std;

            typedef int (*A) (char, char);

            int ss(char a, char b)
            {
                cout<<"功能1"<<endl;

                cout<<a<<endl;

                cout<<b<<endl;

                return 0;
            }
             
            int bb(char a, char b)
            {

                cout<<"功能2"<<endl;

                cout<<b<<endl;

                cout<<a<<endl;

                return 0;

            }

            void main()
            {

                A a;

                a = ss;

                a('a','b');

                a = bb;

                a('a', 'b');
            }

            2.比較二:

            typedef int (A) (char, char);

            void main()
            {

                A *a;

                a = ss;

                a('a','b');

                a = bb;

                a('a','b');
            }
             

            兩個(gè)程序的結(jié)果都一樣:

            功能1

            a

            b

            功能2

            b

            a

             

            *****以下是參考部分*****

            參考自:http://blog.hc360.com/portal/personShowArticle.do?articleId=57527

            typedef 與 #define的區(qū)別:

            案例一:

            通常講,typedef要比#define要好,特別是在有指針的場(chǎng)合。請(qǐng)看例子:

            typedef char *pStr1;

            #define pStr2 char *;

            pStr1 s1, s2;

            pStr2 s3, s4;
            在上述的變量定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們

            所預(yù)期的指針變量,根本原因就在于#define只是簡(jiǎn)單的字符串替換而typedef則是為一

            個(gè)類型起新名字。

            案例二:

            下面的代碼中編譯器會(huì)報(bào)一個(gè)錯(cuò)誤,你知道是哪個(gè)語句錯(cuò)了嗎?

            typedef char * pStr;

            char string[4] = "abc";

            const char *p1 = string;

            const pStr p2 = string;

            p1++;

            p2++;

              是p2++出錯(cuò)了。這個(gè)問題再一次提醒我們:typedef和#define不同,它不是簡(jiǎn)單的

            文本替換。上述代碼中const pStr p2并不等于const char * p2。const pStr p2和

            const long x本質(zhì)上沒有區(qū)別,都是對(duì)變量進(jìn)行只讀限制,只不過此處變量p2的數(shù)據(jù)類

            型是我們自己定義的而不是系統(tǒng)固有類型而已。因此,const pStr p2的含義是:限定數(shù)

            據(jù)類型為char *的變量p2為只讀,因此p2++錯(cuò)誤。雖然作者在這里已經(jīng)解釋得很清楚了,可我在這個(gè)地方仍然還是糊涂的,真的希望哪位高手能幫忙指點(diǎn)一下,特別是這一句“只不過此處變量p2的數(shù)據(jù)類型是我們自己定義的而不是系統(tǒng)固有類型而已”,難道自己定義的類型前面用const修飾后,就不能執(zhí)行更改運(yùn)算,而系統(tǒng)定義的類型卻可以?

            本文轉(zhuǎn)自:
            http://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html

            posted @ 2013-02-20 17:19 王海光 閱讀(494) | 評(píng)論 (0)編輯 收藏
            1、Replace函數(shù)替換查找

            Replace函數(shù)返回值:返回被替換的字符數(shù)。如果這個(gè)字符串沒有改變則返回零。

            CString sTest="aabbccaadd";
            int nCount=s.Replace("a","a");

            nCount
            就是你的想要的值

            CString::Replace
            int Replace( TCHAR chOld, TCHAR chNew );
            int Replace( LPCTSTR lpszOld, LPCTSTR lpszNew );

            Return Value
            The number of replaced instances of the character. Zero if the string isn't changed.


            2、標(biāo)準(zhǔn)函數(shù) count_if

            #include <iostream>
            #include <string>
            #include <functional>
            #include <algorithm>
            using namespace std;

            int main( void )
            {
                const string a = " 12113";
                cout << count_if( a.begin(), a.end(), bind2nd(equal_to<char>(),'1') ) << endl;

                return 0;
            }

            CString也一樣,但它沒有標(biāo)準(zhǔn)的迭代器,因此需要寫成
            count_if( (LPCTSTR)a, (LPCTSTR)a+a.GetLength(), bind2nd(equal_to<TCHAR>(),_T('某字符')) )
            posted @ 2013-02-19 14:34 王海光 閱讀(11983) | 評(píng)論 (2)編輯 收藏

            說說異或運(yùn)算^和他的一個(gè)常用作用。
            異或的運(yùn)算方法是一個(gè)二進(jìn)制運(yùn)算:
            1^1=0
            0^0=0
            1^0=1
            0^1=1

            兩者相等為0,不等為1.

            這樣我們發(fā)現(xiàn)交換兩個(gè)整數(shù)的值時(shí)可以不用第三個(gè)參數(shù)。
            如a=11,b=9.以下是二進(jìn)制
            a=a^b=1011^1001=0010;
            b=b^a=1001^0010=1011;
            a=a^b=0010^1011=1001;
            這樣一來a=9,b=13了。


            舉一個(gè)運(yùn)用, 按一個(gè)按鈕交換兩個(gè)mc的位置可以這樣。

            mybt.onPress=function()
            {
            mc1._x=mc1._x^mc2._x;
            mc2._x=mc2._x^mc1._x;
            mc1._x=mc1._x^mc2._x;
            //
            mc1._y=mc1._y^mc2._y;
            mc2._y=mc2._y^mc1._y;
            mc1._y=mc1._y^mc2._y;
            }

            這樣就可以不通過監(jiān)時(shí)變量來傳遞了。

            最后要聲明:只能用于整數(shù)。

             

            1. 位運(yùn)算 請(qǐng)點(diǎn)評(píng)

            整數(shù)在計(jì)算機(jī)中用二進(jìn)制的位來表示,C語言提供一些運(yùn)算符可以直接操作整數(shù)中的位,稱為位運(yùn)算,這些運(yùn)算符的操作數(shù)都必須是整型的。在以后的學(xué)習(xí)中你會(huì)發(fā)現(xiàn),有些信息利用整數(shù)中的某幾個(gè)位來存儲(chǔ),要訪問這些位,僅僅有對(duì)整數(shù)的操作是不夠的,必須借助位運(yùn)算,例如第 2 節(jié) “Unicode和UTF-8” 介紹的UTF-8編碼就是如此,學(xué)完本節(jié)之后你應(yīng)該能自己寫出UTF-8的編碼和解碼程序。本節(jié)首先介紹各種位運(yùn)算符,然后介紹與位運(yùn)算有關(guān)的編程技巧。

            1.1. 按位與、或、異或、取反運(yùn)算 請(qǐng)點(diǎn)評(píng)

            第 3 節(jié) “布爾代數(shù)” 講過邏輯與、或、非運(yùn)算,并列出了真值表,對(duì)于整數(shù)中的位也可以做與、或、非運(yùn)算,C語言提供了按位與(Bitwise AND)運(yùn)算符&、按位或(Bitwise OR)運(yùn)算符|和按位取反(Bitwise NOT)運(yùn)算符~,此外還有按位異或(Bitwise XOR)運(yùn)算符^,我們?cè)?a style="color: #336699; text-decoration: initial;">第 1 節(jié) “為什么計(jì)算機(jī)用二進(jìn)制計(jì)數(shù)” 講過異或運(yùn)算。下面用二進(jìn)制的形式舉幾個(gè)例子。

            圖 16.1. 位運(yùn)算

            位運(yùn)算

            注 意,&、|、^運(yùn)算符都是要做Usual Arithmetic Conversion的(其中有一步是Integer Promotion),~運(yùn)算符也要做Integer Promotion,所以在C語言中其實(shí)并不存在8位整數(shù)的位運(yùn)算,操作數(shù)在做位運(yùn)算之前都至少被提升為int 型了,上面用8位整數(shù)舉例只是為了書寫方便。比如:

            unsigned char c = 0xfc;
            unsigned int i = ~c;

            計(jì)算過程是這樣的:常量0xfc是int 型的,賦給c 要轉(zhuǎn)成unsigned char ,值不變;c 的十六進(jìn)制表示是fc,計(jì)算~c 時(shí)先提升為整型(000000fc)然后取反,最后結(jié)果是ffffff03。注意,如果把~c 看成是8位整數(shù)的取反,最后結(jié)果就得3了,這就錯(cuò)了。為了避免出錯(cuò),一是盡量避免不同類型之間的賦值,二是每一步計(jì)算都要按上一章講的類型轉(zhuǎn)換規(guī)則仔細(xì)檢查。

            1.2. 移位運(yùn)算 請(qǐng)點(diǎn)評(píng)

            移位運(yùn)算符(Bitwise Shift)包括左移<<和右移>>。左移將一個(gè)整數(shù)的各二進(jìn)制位全部左移若干位,例如0xcfffffff3<<2得到0x3fffffcc:

            圖 16.2. 左移運(yùn)算

            左移運(yùn)算

            最高兩位的11被移出去了,最低兩位又補(bǔ)了兩個(gè)0,其它位依次左移兩位。但要注意,移動(dòng)的位數(shù)必須小于左操作數(shù)的總位數(shù),比如上面的例子,左邊是unsigned int 型,如果左移的位數(shù)大于等于32位,則結(jié)果是Undefined。移位運(yùn)算符不同于+ - * / ==等運(yùn)算符,兩邊操作數(shù)的類型不要求一致,但兩邊操作數(shù)都要做Integer Promotion,整個(gè)表達(dá)式的類型和左操作數(shù)提升后的類型相同。

            復(fù)習(xí)一下第 2 節(jié) “不同進(jìn)制之間的換算” 講過的知識(shí)可以得出結(jié)論,在一定的取值范圍內(nèi),將一個(gè)整數(shù)左移1位相當(dāng)于乘以2 。比如二進(jìn)制11(十進(jìn)制3)左移一位變成110,就是6,再左移一位變成1100,就是12。讀者可以自己驗(yàn)證這條規(guī)律對(duì)有符號(hào)數(shù)和無符號(hào)數(shù)都成立,對(duì)負(fù)數(shù)也成立。當(dāng)然,如果左移改變了最高位(符號(hào)位),那么結(jié)果肯定不是乘以2了,所以我加了個(gè)前提“在一定的取值范圍內(nèi) ”。由于計(jì)算機(jī)做移位比做乘法快得多,編譯器可以利用這一點(diǎn)做優(yōu)化,比如看到源代碼中有i * 8 ,可以編譯成移位指令而不是乘法指令。

            當(dāng)操作數(shù)是無符號(hào)數(shù)時(shí),右移運(yùn)算的規(guī)則和左移類似,例如0xcfffffff3>>2得到0x33fffffc:

            圖 16.3. 右移運(yùn)算

            右移運(yùn)算

            最低兩位的11被移出去了,最高兩位又補(bǔ)了兩個(gè)0,其它位依次右移兩位。和左移類似,移動(dòng)的位數(shù)也必須小于左操作數(shù)的總位數(shù),否則結(jié)果是Undefined。在一定的取值范圍內(nèi),將一個(gè)整數(shù)右移1位相當(dāng)于除以2,小數(shù)部分截掉。

            當(dāng)操作數(shù)是有符號(hào)數(shù)時(shí),右移運(yùn)算的規(guī)則比較復(fù)雜:

            • 如果是正數(shù),那么高位移入0

            • 如果是負(fù)數(shù),那么高位移入1還是0不一定,這是Implementation-defined的。對(duì)于x86平臺(tái)的gcc 編譯器,最高位移入1,也就是仍保持負(fù)數(shù)的符號(hào)位,這種處理方式對(duì)負(fù)數(shù)仍然保持了“右移1位相當(dāng)于除以2 ”的性質(zhì)。

            綜上所述,由于類型轉(zhuǎn)換和移位等問題,用有符號(hào)數(shù)做位運(yùn)算是很不方便的,所以,建議只對(duì)無符號(hào)數(shù)做位運(yùn)算,以減少出錯(cuò)的可能 。

            1、下面兩行printf 打印的結(jié)果有何不同?請(qǐng)讀者比較分析一下。%x 轉(zhuǎn)換說明的含義詳見第 2.9 節(jié) “格式化I/O函數(shù)” 。

            int i = 0xcffffff3;
            printf("%x/n", 0xcffffff3>>2);
            printf("%x/n", i>>2);

            如果要對(duì)一個(gè)整數(shù)中的某些位進(jìn)行操作,怎樣表示這些位在整數(shù)中的位置呢?可以用掩碼(Mask)來表示。比如掩碼0x0000ff00表示對(duì)一個(gè)32位整數(shù)的8~15位進(jìn)行操作,舉例如下。

            1、取出8~15位。

            unsigned int a, b, mask = 0x0000ff00;
            a = 0x12345678;
            b = (a & mask) >> 8; /* 0x00000056 */

            這樣也可以達(dá)到同樣的效果:

            b = (a >> 8) & ~(~0U << 8);

            2、將8~15位清0。

            unsigned int a, b, mask = 0x0000ff00;
            a = 0x12345678;
            b = a & ~mask; /* 0x12340078 */

            3、將8~15位置1。

            unsigned int a, b, mask = 0x0000ff00;
            a = 0x12345678;
            b = a | mask; /* 0x1234ff78 */

            1、統(tǒng)計(jì)一個(gè)無符號(hào)整數(shù)的二進(jìn)制表示中1的個(gè)數(shù),函數(shù)原型是int countbit(unsigned int x); 。

            2、用位操作實(shí)現(xiàn)無符號(hào)整數(shù)的乘法運(yùn)算,函數(shù)原型是unsigned int multiply(unsigned int x, unsigned int y); 。例如:(11011)2 ×(10010)2 =((11011)2 <<1)+((11011)2 <<4)。

            3、對(duì)一個(gè)32位無符號(hào)整數(shù)做循環(huán)右移,函數(shù)原型是unsigned int rotate_right(unsigned int x, int n); 。所謂循環(huán)右移就是把低位移出去的部分再補(bǔ)到高位上去,例如rotate_right(0xdeadbeef, 8) 的值應(yīng)該是0xefdeadbe。

            1.4. 異或運(yùn)算的一些特性 請(qǐng)點(diǎn)評(píng)

            1、一個(gè)數(shù)和自己做異或的結(jié)果是0。如果需要一個(gè)常數(shù)0,x86平臺(tái)的編譯器可能會(huì)生成這樣的指令:xorl %eax, %eax 。不管eax 寄存器里的值原來是多少,做異或運(yùn)算都能得到0,這條指令比同樣效果的movl $0, %eax 指令快,直接對(duì)寄存器做位運(yùn)算比生成一個(gè)立即數(shù)再傳送到寄存器要快一些。

            2、從異或的真值表可以看出,不管是0還是1,和0做異或保持原值不變,和1做異或得到原值的相反值。可以利用這個(gè)特性配合掩碼實(shí)現(xiàn)某些位的翻轉(zhuǎn),例如:

            unsigned int a, b, mask = 1U << 6;
            a = 0x12345678;
            b = a ^ mask; /* flip the 6th bit */

            3、如果a1 ^ a2 ^ a3 ^ ... ^ an 的結(jié)果是1,則表示a1 、a2 、a3 ...an 之中1的個(gè)數(shù)為奇數(shù)個(gè),否則為偶數(shù)個(gè)。這條性質(zhì)可用于奇偶校驗(yàn)(Parity Check),比如在串口通信過程中,每個(gè)字節(jié)的數(shù)據(jù)都計(jì)算一個(gè)校驗(yàn)位,數(shù)據(jù)和校驗(yàn)位一起發(fā)送出去,這樣接收方可以根據(jù)校驗(yàn)位粗略地判斷接收到的數(shù)據(jù)是否有誤。

            4、x ^ x ^ y == y,因?yàn)閤 ^ x == 0,0 ^ y == y。這個(gè)性質(zhì)有什么用呢?我們來看這樣一個(gè)問題:交換兩個(gè)變量的值,不得借助額外的存儲(chǔ)空間,所以就不能采用temp = a; a = b; b = temp; 的辦法了。利用位運(yùn)算可以這樣做交換:

            a = a ^ b;
            b = b ^ a;
            a = a ^ b;

            分析一下這個(gè)過程。為了避免混淆,把a(bǔ)和b的初值分別記為a0 和b0 。第一行,a = a0 ^ b0 ;第二行,把a(bǔ)的新值代入,得到b = b0 ^ a0 ^ b0 ,等號(hào)右邊的b0 相當(dāng)于上面公式中的x,a0 相當(dāng)于y,所以結(jié)果為a0 ;第三行,把a(bǔ)和b的新值代入,得到a = a0 ^ b0 ^ a0 ,結(jié)果為b0 。注意這個(gè)過程不能把同一個(gè)變量自己跟自己交換,而利用中間變量temp 則可以交換。

            1、請(qǐng)?jiān)诰W(wǎng)上查找有關(guān)RAID(Redundant Array of Independent Disks,獨(dú)立磁盤冗余陣列)的資料,理解其實(shí)現(xiàn)原理,其實(shí)就是利用了本節(jié)的性質(zhì)3和4。

            2、交換兩個(gè)變量的值,不得借助額外的存儲(chǔ)空間,除了本節(jié)講的方法之外你還能想出什么方法?本節(jié)講的方法不能把同一個(gè)變量自己跟自己交換,你的方法有沒有什么局限性?

            本文轉(zhuǎn)自:http://blog.csdn.net/yunyuehu/article/details/5408446#t1

            posted @ 2013-01-18 11:07 王海光 閱讀(930) | 評(píng)論 (0)編輯 收藏
            示例代碼:
            DWORD CCommonFun::GetDesignatedDiskFreeSpace(const CString &szPath)
            {
                DWORD dwTotalDiskSpace,dwFreeDiskSpace,dwUsedDiskSpace;    

                ULARGE_INTEGER uiFreeBytesAvailableToCaller;
                ULARGE_INTEGER uiTotalNumberOfBytes;
                ULARGE_INTEGER uiTotalNumberOfFreeBytes;

                if(GetDiskFreeSpaceEx(szPath, &uiFreeBytesAvailableToCaller,
                    &uiTotalNumberOfBytes,
                    &uiTotalNumberOfFreeBytes))
                {
                    dwTotalDiskSpace = (DWORD)(uiTotalNumberOfBytes.QuadPart / 1024 / 1024);
                    dwFreeDiskSpace  = (DWORD)(uiFreeBytesAvailableToCaller.QuadPart >> 20);
                    dwUsedDiskSpace     = dwTotalDiskSpace - dwFreeDiskSpace;
                    TRACE("硬盤%s::總空間%dMB, 已用%dMB, 可用%dMB\n", szPath,
                        dwTotalDiskSpace, dwUsedDiskSpace, dwFreeDiskSpace);

                    return dwFreeDiskSpace;
                }

                return -1;
            }
            posted @ 2013-01-16 17:00 王海光 閱讀(2948) | 評(píng)論 (0)編輯 收藏
            變灰代碼:
            CMenu*   menu   =   this->GetSystemMenu(FALSE);   
            menu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);

            恢復(fù)代碼:
            CMenu*   menu   =   this->GetSystemMenu(FALSE);   
            menu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
            posted @ 2013-01-16 16:57 王海光 閱讀(928) | 評(píng)論 (0)編輯 收藏
            MFC另存為和保存對(duì)話框:

            CString sPath;
            TCHAR szFilters[]=_T("All files(*.*)|*.*||");
            CFileDialog dlg(nFlag,NULL,_T(m_strTime),OFN_HIDEREADONLY| OFN_OVERWRITEPROMPT,szFilters);
            dlg.m_ofn.lpstrInitialDir=_T("c:\\");
            if(IDOK==dlg.DoModal())
            {
                sPath=dlg.GetPathName();
            }
            nFlag值為true時(shí),是保存對(duì)話框,為false時(shí)是另存為對(duì)話框,m_strTime為默認(rèn)文件名字。


            MFC彈出選擇目錄對(duì)話框:

            LPMALLOC lpMalloc;
            if(::SHGetMalloc(&lpMalloc)!=NOERROR)
            {
            AfxMessageBox("選擇下載目錄操作出錯(cuò)");
            return;
            }
            char szDisplayName[_MAX_PATH];
            char szBuffer[_MAX_PATH];
            BROWSEINFO browseInfo;
            browseInfo.hwndOwner=this->m_hWnd;
            browseInfo.pidlRoot=NULL;
            browseInfo.pszDisplayName=szDisplayName;
            browseInfo.lpszTitle="請(qǐng)選擇下載文件的存儲(chǔ)路徑";
            browseInfo.ulFlags=BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS;
            browseInfo.lpfn=NULL;
            browseInfo.lParam=0;
            LPITEMIDLIST lpItemIDList;
            if((lpItemIDList=::SHBrowseForFolder(&browseInfo))!=NULL)
            {
            if(::SHGetPathFromIDList(lpItemIDList,szBuffer))
            {
            if(szBuffer[0]=='\0')
            {
            AfxMessageBox("Fail to get directory",MB_ICONSTOP|MB_OK);
            return;
            }
            DownFileDirectory=szBuffer;
            }
            else
            {
            AfxMessageBox("Fail to get directory!",MB_ICONSTOP|MB_OK);
            return;
            }
            lpMalloc->Free(lpItemIDList);
            lpMalloc->Release();
            }
            CString strMsg;
            strMsg.Format("選擇目錄為:%s",DownFileDirectory);
            AfxMessageBox(strMsg);
            posted @ 2013-01-10 16:25 王海光 閱讀(1477) | 評(píng)論 (0)編輯 收藏

            轉(zhuǎn)自:http://www.itivy.com/ivy/archive/2011/11/24/something-that-architecture-must-be-aware-of.html

            對(duì)于大多數(shù)架構(gòu)師而言,“可擴(kuò)展性”在軟件架構(gòu)方面是最虛無縹緲的說法。這毫不奇怪,因?yàn)榭蓴U(kuò)展性正是如今軟件設(shè)計(jì)領(lǐng)域最值得優(yōu)先考慮的要素。然 而,計(jì)算機(jī)科學(xué)家們還無法了解一套單獨(dú)的架構(gòu)如何才能擴(kuò)展至各類應(yīng)用環(huán)境當(dāng)中。相反,我們?cè)跀?shù)量繁多的方案中所設(shè)計(jì)出的可擴(kuò)展性架構(gòu),往往以業(yè)界較為通用 的已知可擴(kuò)展模式及個(gè)人偏好為標(biāo)準(zhǔn)。簡(jiǎn)單來講,打造一套具備可擴(kuò)展性的系統(tǒng)已經(jīng)變得更像是一門藝術(shù)而不單單是技術(shù)。

            我們常常會(huì)通過觀摩杰作體會(huì)并學(xué)習(xí)藝術(shù)的精髓,而可擴(kuò)展性也應(yīng)該遵循同樣的路線!

            在這篇文章中,我將列出數(shù)款為大家所耳熟能詳?shù)目蓴U(kuò)展性架構(gòu)。通常情況下,架構(gòu)師們完全可以借鑒已知的可擴(kuò)展架構(gòu)模式,進(jìn)而創(chuàng)造出新的可擴(kuò)展架構(gòu)。

            1. LB (負(fù)載平衡器) + 無共享單位 - 該模型中包含一系列單元,各單元彼此間不共享任何內(nèi)容,且一致指向一個(gè)將輸入文訊按一定條件發(fā)往單元處的負(fù)載平衡器(這構(gòu)成一個(gè)循 環(huán),以負(fù)載等情況為基礎(chǔ))。每個(gè)單元可以是一個(gè)單獨(dú)的節(jié)點(diǎn)或是緊密耦合的節(jié)點(diǎn)所構(gòu)成的集群。用戶可以使用DNS循環(huán)、硬件負(fù)載平衡器或者軟件負(fù)載平衡器達(dá) 成負(fù)載平衡效果。創(chuàng)建一套負(fù)載均衡的層次結(jié)構(gòu),并在其中結(jié)合前面提到的各種負(fù)載平衡器也是可行的。在由Michael Stonebraker撰寫的《 無共享體系架構(gòu)實(shí)例 》一文中,專門討論了此類架構(gòu)。
               
            2. LB + 無狀態(tài)節(jié)點(diǎn) + 可擴(kuò)展存儲(chǔ) - 傳統(tǒng)的 三層式Web架構(gòu) 使用的就是這種模型。該模型包括數(shù)個(gè)與可擴(kuò)展存儲(chǔ)交互的無狀態(tài)節(jié)點(diǎn)以及一個(gè)分布于節(jié)點(diǎn)間負(fù)載中的負(fù)載平衡器。在這一模型中,存儲(chǔ)通常作為限制因素存在,但NoSQL存儲(chǔ)則可以利用這套模型創(chuàng)建出具備相當(dāng)可擴(kuò)展性的系統(tǒng)。
               
            3. 點(diǎn)對(duì)點(diǎn)架構(gòu) (分布式Hash列表 (簡(jiǎn)稱DHT)以及內(nèi)容尋址網(wǎng)絡(luò)(簡(jiǎn)稱CAN)) -這套模型提供了一些傳統(tǒng)的 可擴(kuò)展算法,這些算法的各個(gè)方面幾乎全部按對(duì)數(shù)進(jìn)行了等比例增加。舉例來說,像Chord、Pastry(特指免費(fèi)版)以及CAN都屬于此類。而以 Cassandra為代表的、基于P2P架構(gòu)的幾款NoSQL系統(tǒng)也是其中的成員。《 展望P2P系統(tǒng)中的數(shù)據(jù) 》一文就深入探討了這類模型的各種細(xì)節(jié)。
               
            4. 分布式隊(duì)列 – 這種模型以將隊(duì)列實(shí)施(即先進(jìn)先出交付機(jī)制)作為網(wǎng)絡(luò)服務(wù)處理為基礎(chǔ)。該模型通過JMS隊(duì)列而廣泛得到采用。一般會(huì)遵循這種做法的有任務(wù)隊(duì)列以及通過保持隊(duì)列分級(jí)體系實(shí)現(xiàn)擴(kuò)展性的任務(wù)隊(duì)列版本,后者在負(fù)載無法及時(shí)處理時(shí),任務(wù)會(huì)由低級(jí)層面向高級(jí)層面?zhèn)鬟f。
               
            5. 發(fā)布/訂閱模式 - 一般用于通過網(wǎng)絡(luò)向彼此發(fā)布訂閱訊息。《 發(fā)布與訂閱的多面性 》這一經(jīng)典論文中詳細(xì)的介紹這一模型,該模型方面最典型的例子即 NaradaBroker與 EventJava 
               
            6. 小道消息與自然靈感式模型 - 這種模型源自日常生活中小道消息的傳播途徑,也就是每個(gè)節(jié)點(diǎn)將隨機(jī)選擇后續(xù)節(jié)點(diǎn)以交 換信息。正如現(xiàn)實(shí)生活中的實(shí)際反饋,這種八卦型算法在信息傳播方面出奇地迅速。該模型的另一大分支則是受到生物學(xué)影響的啟發(fā)式算法。自然世界中存在著大量 協(xié)調(diào)及擴(kuò)展方面極為卓越的固有算法。舉例來說,螞蟻、人類以及蜜蜂等等,都能夠以最簡(jiǎn)潔的交流方式協(xié)調(diào)好擴(kuò)展性方面的需要。模型中的算法正是借鑒了這些實(shí) 際存在的現(xiàn)象。在論文《 從流行病的蔓延到分布式計(jì)算 》中對(duì)這種模型有著詳盡的敘述。
               
            7. 地圖縮小/數(shù)據(jù)流 - 這一概念首先由谷歌公司提出,地圖縮小為工作的描述及執(zhí)行提供了一套可擴(kuò)展的模式。雖然內(nèi)容 簡(jiǎn)單,但它仍然成為聯(lián)機(jī)分析處理方面的首要處理模式。數(shù)據(jù)流則是一種更先進(jìn)的方式,用來表達(dá)執(zhí)行信息;而像Dryad及Pig這樣的項(xiàng)目為數(shù)據(jù)流的執(zhí)行提 供了可擴(kuò)展的框架。論文《 地圖縮小:大型集群上的簡(jiǎn)化數(shù)據(jù)處理 》中設(shè)置了專門的主題,詳細(xì)討論這一內(nèi)容。Apache的Hadoop就是這種模型的代表性產(chǎn)品。
               
            8. 責(zé)任樹形圖 - 這種模型打破了遞歸問題的束縛,將整個(gè)流程以樹狀形式加以處理;每個(gè)父節(jié)點(diǎn)將工作下放至子節(jié)點(diǎn)。這種模型擴(kuò)展性強(qiáng),并已經(jīng)被應(yīng)用于數(shù)款可擴(kuò)展性架構(gòu)當(dāng)中。
               
            9. 流處理 - 這種模型被用于處理源源不斷的數(shù)據(jù)流及數(shù)據(jù)。這種處理方式通過網(wǎng)絡(luò)中的處理節(jié)點(diǎn)獲得支持(例如Aurora、Twitter Strom以及Apache S4等)。
               
            10. 可擴(kuò)展存儲(chǔ) – 該模型的應(yīng)用范圍從數(shù)據(jù)庫(kù)、NoSQL存儲(chǔ)、服務(wù)注冊(cè)到文件系統(tǒng)都有體現(xiàn)。 鏈接中的這篇文章 以可擴(kuò)展性為切入點(diǎn)對(duì)其進(jìn)行了深入討論。

            綜上所述,可擴(kuò)展性的實(shí)現(xiàn)只有三種方式,即:分布、緩存及異步處理。前文所提到的各種架構(gòu)事實(shí)上都是把這三種方式進(jìn)行不同組合并加以實(shí)施。而另一方 面,不利于可擴(kuò)展性的因素,除了糟糕的編碼本身,全局性協(xié)調(diào)也起到了重要的影響。簡(jiǎn)單來說,任何一種全局性協(xié)調(diào)都會(huì)限制系統(tǒng)的可擴(kuò)展性。本文中所提到的各 種架構(gòu)也只是在做好了本地性協(xié)調(diào),而非全局性協(xié)調(diào)。

            然而,將它們有機(jī)地結(jié)合起來以創(chuàng)建一套極具可擴(kuò)展性的架構(gòu)可不像說起來那么容易,除非我們能找到一種全新的擴(kuò)展模式。不過經(jīng)驗(yàn)告訴我們,比起搞一套全新的架構(gòu),采用為我們所熟知且更易駕馭的可擴(kuò)展性解決方案永遠(yuǎn)是更好的選擇。

            posted @ 2013-01-07 16:49 王海光 閱讀(530) | 評(píng)論 (0)編輯 收藏

            轉(zhuǎn)自:http://www.infoq.com/cn/articles/cyw-evaluate-seachengine-result-quality

            前言

            搜索質(zhì)量評(píng)估是搜索技術(shù)研究的基礎(chǔ)性工作,也是核心工作之一。評(píng)價(jià)(Metrics)在搜索技術(shù)研發(fā)中扮演著重要角色,以至于任何一種新方法與他們的評(píng)價(jià)方式是融為一體的。


            搜索引擎結(jié)果的好壞與否,體現(xiàn)在業(yè)界所稱的在相關(guān)性(Relevance)上。相關(guān)性的定義包括狹義和廣義兩方面,狹義的解釋是:檢索結(jié)果和用戶查詢的相關(guān)程度。而從廣義的層面,相關(guān)性可以理解為為用戶查詢的綜合滿意度。直觀的來看,從用戶進(jìn)入搜索框的那一刻起,到需求獲得滿足為止,這之間經(jīng)歷的過程越順暢,越便捷,搜索相關(guān)性就越好。本文總結(jié)業(yè)界常用的相關(guān)性評(píng)價(jià)指標(biāo)和量化評(píng)價(jià)方法。供對(duì)此感興趣的朋友參考。

            Cranfield評(píng)價(jià)體系

            A Cranfield-like approach這個(gè)名稱來源于英國(guó)Cranfield University,因?yàn)樵诙兰o(jì)五十年代該大學(xué)首先提出了這樣一套評(píng)價(jià)系統(tǒng):由查詢樣例集、正確答案集、評(píng)測(cè)指標(biāo)構(gòu)成的完整評(píng)測(cè)方案,并從此確立了“評(píng)價(jià)”在信息檢索研究中的核心地位。

            Cranfield評(píng)價(jià)體系由三個(gè)環(huán)節(jié)組成:

            1. 抽取代表性的查詢?cè)~,組成一個(gè)規(guī)模適當(dāng)?shù)募?/li>
            2. 針對(duì)查詢樣例集合,從檢索系統(tǒng)的語料庫(kù)中尋找對(duì)應(yīng)的結(jié)果,進(jìn)行標(biāo)注(通常人工進(jìn)行)
            3. 將查詢?cè)~和帶有標(biāo)注信息的語料庫(kù)輸入檢索系統(tǒng),對(duì)系統(tǒng)反饋的檢索結(jié)果,使用預(yù)定義好的評(píng)價(jià)計(jì)算公式,用數(shù)值化的方法來評(píng)價(jià)檢索系統(tǒng)結(jié)果和標(biāo)注的理想結(jié)果的接近程度

            查詢?cè)~集合的選取

            Cranfield評(píng)價(jià)系統(tǒng)在各大搜索引擎公司內(nèi)有廣泛的應(yīng)用。具體應(yīng)用時(shí),首先需要解決的問題是構(gòu)造一個(gè)測(cè)試用查詢?cè)~集合。

            按照Andrei Broder(曾在AltaVista/IBM/Yahoo任職)的研究,查詢?cè)~可分為3類:尋址類查詢(Navigational)、信息類查詢(Informational)、事務(wù)類查詢(Transactional)。對(duì)應(yīng)的比例分別為

            Navigational : 12.3%  Informational : 62.0%  Transactional : 25.7% 

            為了使得評(píng)估符合線上實(shí)際情況,通常查詢?cè)~集合也會(huì)按比例進(jìn)行選取。通常從線上用戶的Query Log文件中自動(dòng)抽取。

            另外查詢集合的構(gòu)造時(shí),除了上述查詢類型外,還可以考慮Query的頻次,對(duì)熱門query(高頻查詢)、長(zhǎng)尾query(中低頻)分別占特定的比例。

            另外,在抽取Query時(shí),往往Query的長(zhǎng)短也是一個(gè)待考慮的因素。因?yàn)槎蘱uery(單term的查詢)和長(zhǎng)Query(多Term的查詢)排序算法往往會(huì)有一些不同。

            構(gòu)成查詢集合后,使用這些查詢?cè)~,在不同系統(tǒng)(例如對(duì)比百度和Google)或不同技術(shù)間(新舊兩套R(shí)anking算法的環(huán)境)進(jìn)行搜索,并對(duì)結(jié)果進(jìn)行評(píng)分,以決定優(yōu)劣。

            附圖:對(duì)同一Query:“社會(huì)保險(xiǎn)法”,各大搜索引擎的結(jié)果示意圖。下面具體談?wù)勗u(píng)分的方法。

            Precision-recall(準(zhǔn)確率-召回率方法)

            計(jì)算方法

            信息檢索領(lǐng)域最廣為人知的評(píng)價(jià)指標(biāo)為Precision-Recall(準(zhǔn)確率-召回率)方法。該方法從提出至今已經(jīng)歷半個(gè)世紀(jì),至今在很多搜索引擎公司的效果評(píng)估中使用。

            顧名思義,這個(gè)方法由準(zhǔn)確率和召回率這兩個(gè)相互關(guān)聯(lián)的統(tǒng)計(jì)量構(gòu)成:召回率(Recall)衡量一個(gè)查詢搜索到所有相關(guān)文檔的能力,而準(zhǔn)確率(Precision)衡量搜索系統(tǒng)排除不相關(guān)文檔的能力。(通俗的解釋一下:準(zhǔn)確率就是算一算你查詢得到的結(jié)果中有多少是靠譜的;而召回率表示所有靠譜的結(jié)果中,有多少被你給找回來了)。這兩項(xiàng)是評(píng)價(jià)搜索效果的最基礎(chǔ)指標(biāo),其具體的計(jì)算方法如下。

            Precision-recall方法假定對(duì)一個(gè)給定的查詢,對(duì)應(yīng)一個(gè)被檢索的文檔集合和一個(gè)不相關(guān)的文檔集合。這里相關(guān)性被假設(shè)為二元的,用數(shù)學(xué)形式化方法來描述,則是:

            A表示相關(guān)文檔集合

            A表示不相關(guān)集合

            B表示被檢索到的文檔集合

            B表示未被檢索到的文檔集合

            則單次查詢的準(zhǔn)確率和召回率可以用下述公式來表達(dá):

            (運(yùn)算符∩ 表示兩個(gè)集合的交集。|x|符號(hào)表示集合x中的元素?cái)?shù)量)

            從上面的定義不難看出,召回率和準(zhǔn)確率的取值范圍均在[0,1]之間。那么不難想象,如果這個(gè)系統(tǒng)找回的相關(guān)越多,那么召回率越高,如果相關(guān)結(jié)果全部都給召回了,那么recall此時(shí)就等于1.0。

             

            相關(guān)的

            不相關(guān)

            被檢索到

            A∩ B

            A∩ B

            未被檢索到

            A∩B

            AB

            Precision-Recall曲線

            召回率和準(zhǔn)確率分別反映了檢索系統(tǒng)的兩個(gè)最重要的側(cè)面,而這兩個(gè)側(cè)面又相互制約。因?yàn)榇笠?guī)模數(shù)據(jù)集合中,如果期望檢索到更多相關(guān)的文檔,必然需要“放寬”檢索標(biāo)準(zhǔn),因此會(huì)導(dǎo)致一些不相關(guān)結(jié)果混進(jìn)來,從而使準(zhǔn)確率受到影響。類似的,期望提高準(zhǔn)確率,將不相關(guān)文檔盡量去除時(shí),務(wù)必要執(zhí)行更“嚴(yán)格”的檢索策略,這樣也會(huì)使一些相關(guān)的文檔被排除在外,使召回率下降。

            所以為了更清晰的描述兩者間的關(guān)系,通常我們將Precison-Recall用曲線的方式繪制出來,可以簡(jiǎn)稱為P-R diagram。常見的形式如下圖所示。(通常曲線是一個(gè)逐步向下的走勢(shì),即隨著Recall的提高,Precision逐步降低)

            P-R的其它形態(tài)

            一些特定搜索應(yīng)用,會(huì)更關(guān)注搜索結(jié)果中錯(cuò)誤的結(jié)果。例如,搜索引擎的反作弊系統(tǒng)(Anti-Spam System)會(huì)更關(guān)注檢索結(jié)果中混入了多少條作弊結(jié)果。學(xué)術(shù)界把這些錯(cuò)誤結(jié)果稱作假陽性(False Positive)結(jié)果,對(duì)這些應(yīng)用,通常選擇用虛報(bào)率(Fallout)來統(tǒng)計(jì):

            Fallout和Presion本質(zhì)是完全相同的。只是分別從正反兩方面來計(jì)算。實(shí)際上是P-R的一個(gè)變種。

            再回到上圖,Presion-Recall是一個(gè)曲線,用來比較兩個(gè)方法的效果往往不夠直觀,能不能對(duì)兩者進(jìn)行綜合,直接反映到一個(gè)數(shù)值上呢?為此IR學(xué)術(shù)界提出了F值度量(F -Measure)的方法。F-Measure通過Presion和Recall的調(diào)和平均數(shù)來計(jì)算,公式為:

            其中參數(shù)λε(0,1)調(diào)節(jié)系統(tǒng)對(duì)Precision和Recall的平衡程度。(通常取λ=0.5,此時(shí) 

            這里使用調(diào)和平均數(shù)而不是通常的幾何平均或算術(shù)平均,原因是調(diào)和平均數(shù)強(qiáng)調(diào)較小數(shù)值的重要性,能敏感的反映小數(shù)字的變化,因此更適合用來反映檢索效果。

            使用F Measure的好處是只需要一個(gè)單一的數(shù)字就可以總結(jié)系統(tǒng)的檢索效果,便于比較不同搜索系統(tǒng)的整體效果。

            P@N方法

            點(diǎn)擊因素

            傳統(tǒng)的Precision-Recall并不完全適用對(duì)搜索引擎的評(píng)估,原因是搜索引擎用戶的點(diǎn)擊方式有其特殊性,包括:

            A 60-65%的查詢點(diǎn)擊了名列搜索結(jié)果前10條的網(wǎng)頁;  B 20-25%的人會(huì)考慮點(diǎn)擊名列11到20的網(wǎng)頁;  C 僅有3-4%的會(huì)點(diǎn)擊名列搜索結(jié)果中列第21到第30名的網(wǎng)頁 

            也就是說,絕大部分用戶是不愿意翻頁去看搜索引擎給出的后面的結(jié)果。

            而即使在搜索結(jié)果的首頁(通常列出的是前10條結(jié)果),用戶的點(diǎn)擊行為也很有意思,我們通過下面的Google點(diǎn)擊熱圖(Heat Map)來觀察(這個(gè)熱圖在二維搜索結(jié)果頁上通過光譜來形象的表達(dá)不同位置用戶的點(diǎn)擊熱度。顏色約靠近紅色表示點(diǎn)擊強(qiáng)度越高):

            從圖中可以看出,搜索結(jié)果的前3條吸引了大量的點(diǎn)擊,屬于熱度最高的部分。也就是說,對(duì)搜蘇引擎來說,最前的幾條結(jié)果是最關(guān)鍵的,決定了用戶的滿意程度。

            康乃爾大學(xué)的研究人員通過eye tracking實(shí)驗(yàn)獲得了更為精確的Google搜索結(jié)果的用戶行為分析圖。從這張圖中可以看出,第一條結(jié)果獲得了56.38%的搜索流量,第二條和第三條結(jié)果的排名依次降低,但遠(yuǎn)低于排名第一的結(jié)果。前三條結(jié)果的點(diǎn)擊比例大約為11:3:2 。而前三條結(jié)果的總點(diǎn)擊幾乎分流了搜索流量的80%。

            另外的一些有趣的結(jié)論是,點(diǎn)擊量并不是按照順序依次遞減的。排名第七位獲得的點(diǎn)擊是最少的,原因可能在于用戶在瀏覽過程中下拉頁面到底部,這時(shí)候就只顯示最后三位排名網(wǎng)站,第七名便容易被忽略。而首屏最后一個(gè)結(jié)果獲得的注意力(2.55)是大于倒數(shù)第二位的(1.45),原因是用戶在翻頁前,對(duì)最后一條結(jié)果印象相對(duì)較深。搜索結(jié)果頁面第二頁排名第一的網(wǎng)頁(即總排名11位的結(jié)果)所獲得的點(diǎn)擊只有首頁排名第十網(wǎng)站的40%,與首頁的第一條結(jié)果相比,更是只有其1/60至1/100的點(diǎn)擊量。

            因此在量化評(píng)估搜索引擎的效果時(shí),往往需要根據(jù)以上搜索用戶的行為特點(diǎn),進(jìn)行針對(duì)性的設(shè)計(jì)。

            P@N的計(jì)算方法

            P@N本身是Precision@N的簡(jiǎn)稱,指的是對(duì)特定的查詢,考慮位置因素,檢測(cè)前N條結(jié)果的準(zhǔn)確率。例如對(duì)單次搜索的結(jié)果中前5篇,如果有4篇為相關(guān)文檔,則P@5 = 4/5 = 0.8 。

            測(cè)試通常會(huì)使用一個(gè)查詢集合(按照前文所述方法構(gòu)造),包含若干條不同的查詢?cè)~,在實(shí)際使用P@N進(jìn)行評(píng)估時(shí),通常使用所有查詢的P@N數(shù)據(jù),計(jì)算算術(shù)平均值,用來評(píng)判該系統(tǒng)的整體搜索結(jié)果質(zhì)量。

            N的選取

            對(duì)用戶來說,通常只關(guān)注搜索結(jié)果最前若干條結(jié)果,因此通常搜索引擎的效果評(píng)估只關(guān)注前5、或者前3結(jié)果,所以我們常用的N取值為P@3或P@5等。

            對(duì)一些特定類型的查詢應(yīng)用,如尋址類的查詢(Navigational Search),由于目標(biāo)結(jié)果極為明確,因此在評(píng)估時(shí),會(huì)選擇N=1(即使用P@1)。舉個(gè)例子來說,搜索“新浪網(wǎng)”、或“新浪首頁”,如果首條結(jié)果不是 新浪網(wǎng)(url:www.sina.com.cn),則直接判該次查詢精度不滿足需求,即P@1=0

            MRR

            上述的P@N方法,易于計(jì)算和理解。但細(xì)心的讀者一定會(huì)發(fā)現(xiàn)問題,就是在前N結(jié)果中,排序第1位和第N位的結(jié)果,對(duì)準(zhǔn)確率的影響是一樣的。但實(shí)際情況是,搜索引擎的評(píng)價(jià)是和排序位置極為相關(guān)的。即排第一的結(jié)果錯(cuò)誤,和第10位的結(jié)果錯(cuò)誤,其嚴(yán)重程度有天壤之別。因此在評(píng)價(jià)系統(tǒng)中,需要引入位置這個(gè)因素。

            MRR是平均排序倒數(shù)(Mean Reciprocal Rank)的簡(jiǎn)稱,MRR方法主要用于尋址類檢索(Navigational Search)或問答類檢索(Question Answering),這些檢索方法只需要一個(gè)相關(guān)文檔,對(duì)召回率不敏感,而是更關(guān)注搜索引擎檢索到的相關(guān)文檔是否排在結(jié)果列表的前面。MRR方法首先計(jì)算每一個(gè)查詢的第一個(gè)相關(guān)文檔位置的倒數(shù),然后將所有倒數(shù)值求平均。例如一個(gè)包含三個(gè)查詢?cè)~的測(cè)試集,前5結(jié)果分別為:

            查詢一結(jié)果:1.AN 2.AR 3.AN 4.AN 5.AR  查詢二結(jié)果:1.AN 2.AR 3.AR 4.AR 5.AN  查詢?nèi)Y(jié)果:1.AR 2.AN 3.AN 4.AN 5.AR  

            其中AN表示不相關(guān)結(jié)果,AR表示相關(guān)結(jié)果。那么第一個(gè)查詢的排序倒數(shù)(Reciprocal Rank)RR1 = 1/2=0.5 ;第二個(gè)結(jié)果RR2 = 1/2 = 0.5 ; 注意倒數(shù)的值不變,即使查詢二獲得的相關(guān)結(jié)果更多。同理,RR3= 1/1 = 1。 對(duì)于這個(gè)測(cè)試集合,最終MRR=(RR1+RR2+RR3)/ 3 = 0.67

            然而對(duì)大部分檢索應(yīng)用來說,只有一條結(jié)果無法滿足需求,對(duì)這種情況,需要更合適的方法來計(jì)算效果,其中最常用的是下述MAP方法。

            MAP

            MAP方法是Mean Average Precison,即平均準(zhǔn)確率法的簡(jiǎn)稱。其定義是求每個(gè)相關(guān)文檔檢索出后的準(zhǔn)確率的平均值(即Average Precision)的算術(shù)平均值(Mean)。這里對(duì)準(zhǔn)確率求了兩次平均,因此稱為Mean Average Precision。(注:沒叫Average Average Precision一是因?yàn)殡y聽,二是因?yàn)闊o法區(qū)分兩次平均的意義)

            MAP 是反映系統(tǒng)在全部相關(guān)文檔上性能的單值指標(biāo)。系統(tǒng)檢索出來的相關(guān)文檔越靠前(rank 越高),MAP就應(yīng)該越高。如果系統(tǒng)沒有返回相關(guān)文檔,則準(zhǔn)確率默認(rèn)為0。

            例如:假設(shè)有兩個(gè)主題:

            主題1有4個(gè)相關(guān)網(wǎng)頁,主題2有5個(gè)相關(guān)網(wǎng)頁。

            某系統(tǒng)對(duì)于主題1檢索出4個(gè)相關(guān)網(wǎng)頁,其rank分別為1, 2, 4, 7;

            對(duì)于主題2檢索出3個(gè)相關(guān)網(wǎng)頁,其rank分別為1,3,5。

            對(duì)于主題1,平均準(zhǔn)確率MAP計(jì)算公式為:

            (1/1+2/2+3/4+4/7)/4=0.83。 

            對(duì)于主題2,平均準(zhǔn)確率MAP計(jì)算公式為:

            (1/1+2/3+3/5+0+0)/5=0.45。 

            則MAP= (0.83+0.45)/2=0.64。”

            DCG方法

            DCG是英文Discounted cumulative gain的簡(jiǎn)稱,中文可翻譯為“折扣增益值”。DCG方法的基本思想是:

            1. 每條結(jié)果的相關(guān)性分等級(jí)來衡量
            2. 考慮結(jié)果所在的位置,位置越靠前的則重要程度越高
            3. 等級(jí)高(即好結(jié)果)的結(jié)果位置越靠前則值應(yīng)該越高,否則給予懲罰

            我們首先來看第一條:相關(guān)性分級(jí)。這里比計(jì)算Precision時(shí)簡(jiǎn)單統(tǒng)計(jì)“準(zhǔn)確”或“不準(zhǔn)確”要更為精細(xì)。我們可以將結(jié)果細(xì)分為多個(gè)等級(jí)。比如常用的3級(jí):Good(好)、Fair(一般)、Bad(差)。對(duì)應(yīng)的分值rel為:Good:3 / Fair:2 / Bad:1 。一些更為細(xì)致的評(píng)估使用5級(jí)分類法:Very Good(明顯好)、Good(好)、Fair(一般)、Bad(差)、Very Bad(明顯差),可以將對(duì)應(yīng)分值rel設(shè)置為:Very Good:2 / Good:1 / Fair:0 / Bad:-1 / Very Bad: -2

            評(píng)判結(jié)果的標(biāo)準(zhǔn)可以根據(jù)具體的應(yīng)用來確定,Very Good通常是指結(jié)果的主題完全相關(guān),并且網(wǎng)頁內(nèi)容豐富、質(zhì)量很高。而具體到每條

            DCG的計(jì)算公式并不唯一,理論上只要求對(duì)數(shù)折扣因子的平滑性。我個(gè)人認(rèn)為下面的DCG公式更合理,強(qiáng)調(diào)了相關(guān)性,第1、2條結(jié)果的折扣系數(shù)也更合理:

            此時(shí)DCG前4個(gè)位置上結(jié)果的折扣因子(Discount factor)數(shù)值為:

            i

            log2 (i+1)

            1/log2 (i+1)

            1

            1

            1

            2

            1.59

            0.63

            3

            2

            0.5

            4

            2.32

            0.43

            取以2為底的log值也來自于經(jīng)驗(yàn)公式,并不存在理論上的依據(jù)。實(shí)際上,Log的基數(shù)可以根據(jù)平滑的需求進(jìn)行修改,當(dāng)加大數(shù)值時(shí)(例如使用log5 代替log2),折扣因子降低更為迅速,此時(shí)強(qiáng)調(diào)了前面結(jié)果的權(quán)重。

            為了便于不同類型的query結(jié)果之間橫向比較,以DCG為基礎(chǔ),一些評(píng)價(jià)系統(tǒng)還對(duì)DCG進(jìn)行了歸一,這些方法統(tǒng)稱為nDCG(即 normalize DCG)。最常用的計(jì)算方法是通過除以每一個(gè)查詢的理想值iDCG(ideal DCG)來進(jìn)行歸一,公式為:

            求nDCG需要標(biāo)定出理想情況的iDCG,實(shí)際操作的時(shí)候是異常困難的,因?yàn)槊總€(gè)人對(duì)“最好的結(jié)果”理解往往各不相同,從海量數(shù)據(jù)里選出最優(yōu)結(jié)果是很困難的任務(wù),但是比較兩組結(jié)果哪個(gè)更好通常更容易,所以實(shí)踐應(yīng)用中,通常選擇結(jié)果對(duì)比的方法進(jìn)行評(píng)估。

            怎樣實(shí)現(xiàn)自動(dòng)化的評(píng)估?

            以上所介紹的搜索引擎量化評(píng)估指標(biāo),在Cranfield評(píng)估框架(Cranfield Evaluation Framework)中被廣泛使用。業(yè)界知名的TREC(文本信息檢索會(huì)議)就一直基于此類方法組織信息檢索評(píng)測(cè)和技術(shù)交流。除了TREC外,一些針對(duì)不同應(yīng)用設(shè)計(jì)的Cranfield評(píng)測(cè)論壇也在進(jìn)行進(jìn)行(如 NTCIR、IREX等)。

            但Cranfield評(píng)估框架存在的問題是查詢樣例集合的標(biāo)注上。利用手工標(biāo)注答案的方式進(jìn)行網(wǎng)絡(luò)信息檢索的評(píng)價(jià)是一個(gè)既耗費(fèi)人力、又耗費(fèi)時(shí)間的過程,只有少數(shù)大公司能夠使用。并且由于搜索引擎算法改進(jìn)、運(yùn)營(yíng)維護(hù)的需要,檢索效果評(píng)價(jià)反饋的時(shí)間需要盡量縮短,因此自動(dòng)化的評(píng)測(cè)方法對(duì)提高評(píng)估效率十分重要。最常用的自動(dòng)評(píng)估方法是A/B testing系統(tǒng)。

            A/B Testing

            A/B Testing系統(tǒng)

            A/B testing系統(tǒng)在用戶搜索時(shí),由系統(tǒng)來自動(dòng)決定用戶的分組號(hào)(Bucket id),通過自動(dòng)抽取流量導(dǎo)入不同分支,使得相應(yīng)分組的用戶看到的是不同產(chǎn)品版本(或不同搜索引擎)提供的結(jié)果。用戶在不同版本產(chǎn)品下的行為將被記錄下來,這些行為數(shù)據(jù)通過數(shù)據(jù)分析形成一系列指標(biāo),而通過這些指標(biāo)的比較,最后就形成了各版本之間孰優(yōu)孰劣的結(jié)論。

            在指標(biāo)計(jì)算時(shí),又可細(xì)分為兩種方法,一種是基于專家評(píng)分的方法;一種是基于點(diǎn)擊統(tǒng)計(jì)的方法。

            專家評(píng)分的方法通常由搜索核心技術(shù)研發(fā)和產(chǎn)品人員來進(jìn)行,根據(jù)預(yù)先設(shè)定的標(biāo)準(zhǔn)對(duì)A、B兩套環(huán)境的結(jié)果給予評(píng)分,獲取每個(gè)Query的結(jié)果對(duì)比,并根據(jù)nDCG等方法計(jì)算整體質(zhì)量。

            點(diǎn)擊評(píng)分有更高的自動(dòng)化程度,這里使用了一個(gè)假設(shè):同樣的排序位置,點(diǎn)擊數(shù)量多的結(jié)果質(zhì)量?jī)?yōu)于點(diǎn)擊數(shù)量少的結(jié)果。(即A2表示A測(cè)試環(huán)境第2條結(jié)果,如果A2 > B2,則表示A2質(zhì)量更好)。通俗的說,相信群眾(因?yàn)槿罕姷难劬κ茄┝恋模T谶@個(gè)假設(shè)前提下,我們可以將A/B環(huán)境前N條結(jié)果的點(diǎn)擊率自動(dòng)映射為評(píng)分,通過統(tǒng)計(jì)大量的Query點(diǎn)擊結(jié)果,可以獲得可靠的評(píng)分對(duì)比。

            Interleaving Testing

            另外2003年由Thorsten Joachims 等人提出的Interleaving testing方法也被廣泛使用。該方法設(shè)計(jì)了一個(gè)元搜索引擎,用戶輸入查詢?cè)~后,將查詢?cè)~在幾個(gè)著名搜索引擎中的查詢結(jié)果隨機(jī)混合反饋給用戶,并收集隨后用戶的結(jié)果點(diǎn)擊行為信息.根據(jù)用戶不同的點(diǎn)擊傾向性,就可以判斷搜索引擎返回結(jié)果的優(yōu)劣,

            如下圖所示,將算法A和B的結(jié)果交叉放置,并分流量進(jìn)行測(cè)試,記錄用戶點(diǎn)擊信息。根據(jù)點(diǎn)擊分布來判斷A和B環(huán)境的優(yōu)劣。

            Interleaving Testing評(píng)估方法

            Joachims同時(shí)證明了Interleaving Testing評(píng)價(jià)方法與傳統(tǒng)Cranfield評(píng)價(jià)方法的結(jié)果具有較高的相關(guān)性。由于記錄用戶選擇檢索結(jié)果的行為是一個(gè)不耗費(fèi)人力的過程,因此可以便捷的實(shí)現(xiàn)自動(dòng)化的搜索效果評(píng)估。

            總結(jié)

            沒有評(píng)估就沒有進(jìn)步——對(duì)搜索效果的量化評(píng)測(cè),目的是準(zhǔn)確的找出現(xiàn)有搜索系統(tǒng)的不足(沒有哪個(gè)搜索系統(tǒng)是完美的),進(jìn)而一步一個(gè)腳印對(duì)算法、系統(tǒng)進(jìn)行改進(jìn)。本文為大家總結(jié)了常用的評(píng)價(jià)框架和評(píng)價(jià)指標(biāo)。這些技術(shù)像一把把尺子,度量著搜索技術(shù)每一次前進(jìn)的距離。


            感謝張凱峰對(duì) 本文的審校。

            給InfoQ中文站投稿或者參與內(nèi)容翻譯工作,請(qǐng)郵件至editors@cn.infoq.com。也歡迎大家加入到InfoQ中文站用戶討論組中與我們的編輯和其他讀者 朋友交流。

            posted @ 2013-01-07 16:46 王海光 閱讀(440) | 評(píng)論 (0)編輯 收藏
                 摘要: MySQL索引背后的數(shù)據(jù)結(jié)構(gòu)及算法原理摘要本文以MySQL數(shù)據(jù)庫(kù)為研究對(duì)象,討論與數(shù)據(jù)庫(kù)索引相關(guān)的一些話題。特別需要說明的是,MySQL支持諸多存儲(chǔ)引擎,而各種存儲(chǔ)引擎對(duì)索引的支持也各不相同,因此MySQL數(shù)據(jù)庫(kù)支持多種索引類型,如BTree索引,哈希索引,全文索引等等。為了避免混亂,本文將只關(guān)注于BTree索引,因?yàn)檫@是平常使用MySQL時(shí)主要打交道的索引,至于哈希索引和全文索引本文暫不討論。文...  閱讀全文
            posted @ 2013-01-07 16:43 王海光 閱讀(318) | 評(píng)論 (0)編輯 收藏
            僅列出標(biāo)題
            共27頁: First 7 8 9 10 11 12 13 14 15 Last 
            久久国产免费直播| 97久久精品人人做人人爽| 要久久爱在线免费观看| 亚洲国产成人久久笫一页| 久久天天躁狠狠躁夜夜躁2O2O| 久久99精品国产99久久6男男| 欧美久久天天综合香蕉伊| 粉嫩小泬无遮挡久久久久久| 久久久久久国产精品免费免费| 国产成人精品综合久久久久| 99久久伊人精品综合观看| 亚洲精品成人久久久| 成人精品一区二区久久| 久久久久无码精品国产| 中文精品99久久国产| 久久久91人妻无码精品蜜桃HD| 久久人做人爽一区二区三区| 久久91这里精品国产2020| 一本色道久久99一综合| 久久这里的只有是精品23| 久久精品无码一区二区日韩AV| 高清免费久久午夜精品| 人妻少妇久久中文字幕 | 精产国品久久一二三产区区别| 青青青国产成人久久111网站| 久久久久国产精品熟女影院| 四虎影视久久久免费| 久久久久亚洲?V成人无码| 久久香蕉国产线看观看99| 无码人妻久久久一区二区三区| 亚洲欧美日韩精品久久亚洲区| 国产精品免费看久久久香蕉| 国产午夜福利精品久久2021| 久久午夜伦鲁片免费无码| 精品国产乱码久久久久久郑州公司| 综合人妻久久一区二区精品| 亚洲精品国产美女久久久| 亚洲精品tv久久久久久久久久| 狠狠色丁香久久婷婷综合图片| 2021国产精品午夜久久| 欧洲精品久久久av无码电影|