C 實現字串的包含演算法

2021-08-15 08:57:26 字數 3822 閱讀 7102

這是乙個「演算法之美」書中關於字串的演算法:

題目:給定乙個長字串a和短字串b,如何判斷短字串b中所有字元的是否都在長字串a中?

書中給了這麼幾中解法:

1.暴力輪詢:

對於任何一種演算法都要抱乙個學習的心態去看,首先暴力輪詢在實際的使用中其實還是比較多見的,尤其是我在剛剛從事程式設計的時候,幾乎所有的演算法實現,都或多或少的採用了暴力輪詢的方法,暴力輪詢中,如果字串a長度為m、字串b長度為n,那麼他們的時間複雜度是o(m*n),時間複雜度是穩定的。

而且占用的空間也比較穩定。

方法很簡單,暴力輪詢嘛,將b中的全部元素在a中找一遍,如果發現匹配就b++,如果b[i]在a中遍歷一遍之後,還是沒有發現相同的字元,就return回去表示false。

2.排序後輪詢:

第一種演算法在實現的時候,其實就在想這個問題,既然這個字元匹配的演算法不是「塊匹配」,就是說不是要求字串b在字串a中連續且順序的出現,那我不是可以先排一下序麼?

就算是傳入的是const& 也可以使用一些類似與strcpy的方法把它做乙份副本出來嘛,然後再去做輪詢,時間複雜度就會好很多了。

3.排序後選擇輪詢:

這種演算法是我在做完第二種演算法之後,我沒有看那本演算法的書了,我在想乙個問題,如果說在排序的時候,我要查詢的字元正好在整個字串的末尾位置,舉個例子———— 假設排好序之後string a = "abcdef"  string b = "af",那麼如果現在去做匹配的話,string b中的'a'是可以很快找到,但是我的f就。。。。,當排好序之後,這個問題就從暴力輪詢變味了有序查詢演算法,我們就有很多的選擇去做這個事情:比如二分法,比如斐波拉契法,比如拉格朗日插值查詢、比如。。。。哈! 希 !查!找 !

4.雜湊法:

到現在我覺得我已經知道書中的第4中方法要講的是什麼了,如果要實現雜湊查詢,首先第一件事情是,建立乙個雜湊表,科普一下什麼是雜湊表:

雜湊表(hash table,也叫雜湊表),是根據關鍵碼值(key value)而直接進行訪問的

資料結構

。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做

雜湊函式

,存放記錄的

陣列叫做

雜湊表。給定表m,存在函式f(key),對任意給定的關鍵字值key,代入函式後若能得到包含該關鍵字的記錄在表中的位址,則稱表m為雜湊(hash)表,函式f(key)為雜湊(hash) 函式。

那麼問題就變成了如何去構建乙個適合我們使用的雜湊函式:

再次科普一下什麼是雜湊函式,以及常見的雜湊函式:

雜湊函式

能使對乙個資料序列的訪問過程更加迅速有效,通過雜湊函式,

資料元素

將被更快地定位。

實際工作中需視不同的情況採用不同的

雜湊函式

,通常考慮的因素有:

· 計算

雜湊函式

所需時間

· 關鍵字的長度

· 雜湊表的大小

· 關鍵字的分布情況

· 記錄的查詢頻率

1.直接定址

雜湊函式

叫做自身函式)。若其中h(key)中已經有值了,就往下乙個找,直到h(key)中沒有值了,就放進去。

2. 數字分析法:分析一組資料,比如一組員工的出生年月日,這時我們發現出生年月日的前幾位數字大體相同,這樣的話,出現衝突的機率就會很大,但是我們發現年月日的後幾位表示月份和具體日期的數字差別很大,如果用後面的數字來構成雜湊位址,則衝突的機率會明顯降低。因此數字分析法就是找出數字的規律,盡可能利用這些資料來構造衝突機率較低的雜湊位址。

3. 平方取中法:當無法確定關鍵字中哪幾位分布較均勻時,可以先求出關鍵字的平方值,然後按需要取平方值的中間幾位作為雜湊位址。這是因為:平方後中間幾位和關鍵字中每一位都相關,故不同關鍵字會以較高的概率產生不同的雜湊位址。

[2]例:我們把英文本母在字母表中的位置序號作為該英文本母的內部編碼。例如k的內部編碼為11,e的內部編碼為05,y的內部編碼為25,a的內部編碼為01, b的內部編碼為02。由此組成關鍵字「keya」的內部**為11052501,同理我們可以得到關鍵字「kyab」、「akey」、「bkey」的內部編碼。之後對關鍵字進行平方運算後,取出第7到第9位作為該關鍵字雜湊位址,如下圖所示

關鍵字內部編碼

內部編碼的平方值

h(k)關鍵字的雜湊位址

keya

11050201

122157778355001

778

kyab

11250102

126564795010404

795

akey

01110525

001233265775625

265

bkey

02110525

004454315775625

315

4. 摺疊法:將關鍵字分割成位數相同的幾部分,最後一部分位數可以不同,然後取這幾部分的疊加和(去除進製)作為雜湊位址。數字疊加可以有移位疊加和間界疊加兩種方法。移位疊加是將分割後的每一部分的最低位對齊,然後相加;間界疊加是從一端向另一端沿分割界來回摺疊,然後對齊相加。

5. 隨機數法:選擇一

隨機函式

,取關鍵字的隨機值作為雜湊位址,通常用於關鍵字長度不同的場合。

6. 除留餘數法:取關鍵字被某個不大於

雜湊表表長m的數p除后所得的餘數為雜湊位址。即 h(key) = key mod p,p<=m。不僅可以對

關鍵字直接取模,也可在摺疊、平方取中等運算之後取模。對p的選擇很重要,一般取素數或m,若p選的不好,容易產生同義詞。

雜湊結構是一種著名的用空間換時間的檢索結構,在「演算法之美」的書中,關於第4中方法它是這麼解釋的:

使用位操作實現數字簽名,然後查詢簽名。。。。

bool stringcontain(string &a, string &b)

for (int i = 0; i < b.length(); ++i) }

return true;

}

上述**是我把書中的**做了乙個翻譯,一夥用來吐槽一下這是多麼蠢的乙個做法,在吐槽之前,先解析一下關於這個演算法的原理:

int  tmp的二進:0000 0000 0000 0001

這個時候不斷的對他進行左移操作 與|=操作就是把sting a中每乙個和'a'的距離對映到了32個0、1**中,然後從string b中去找某一位是不是已經有籤。

這個很簡單,只要學過位運算用筆畫畫就行了。同時把這個程式一碼,好像很厲害的樣子哦~

但是如果仔細研究一下就會發現,到處是坑。。。。。。

1.int tmp 是32位數,那麼如果我要左移32位怎麼辦——比如string a = 'ab' string b = 'a',結果竟然是 true!!!

2.如果我輸入的是「中國」,漢字!不是直接蒙蔽?(漢字不走ascii)

所以說上面這個東西只有參考價值,沒有實際價值。所謂的參考價值:簽名的思想,我們其實完全可以用陣列換位操作啊,c/c++中貌似沒有64位以上的變數了吧,但是陣列你玩1個g都行,當然,我們也不需要那麼多。

我們可以使用陣列的思想去做這個事情:

bool stringcontain_new(wstring &a, wstring &b)

{

int *signature_num = new int[1024*1024];

//演算法就是以時間換空間或者反之

int length = a.length();

for(int i = 0;i

演算法 字串包含

給定兩個分別由字母組成的字串a和字串b,字串b的長度比字串a短。請問,如何最快地判斷字串b中所有字母是否都在字串a裡?為了簡單起見,我們規定輸入的字串只包含大寫英文本母,請實現函式bool stringcontains string a,string b 比如,如果是下面兩個字串 string 1 ...

字串包含演算法

題目如下 給定乙個長字串a和短字串b,如何判斷短字串b中所有字元的是否都在長字串a中?方法如下 1.簡單粗暴的方法 蠻力輪詢 不推薦 思路 遍歷字串b中的每乙個字元,判斷該字元是否在字串a中。時間複雜度 o nm 其中n為a的長度,m為b的長度 2.排序後輪詢 思路 先對字串a和字串b進行排序,然後...

字串包含問題演算法

現在假設有2個字串r和s,其中m r.len n s.len,設計乙個演算法判斷字串s中的每個字元在r串中均存在.顯然,很容易想到的乙個演算法,最粗魯最暴力演算法,其時間複雜度o m n 也就是對s字串中的每個字元在r中進行查詢判斷 這或許是我自己想到的最快的方法了。顯而易見,這樣的演算法或許不是演...