常用演算法總結

2022-03-06 19:42:34 字數 4694 閱讀 3032

常用演算法總結

前言與準備工作

動態規劃演算法、貪心演算法、分治演算法、回溯法、分支限界法。(此部分內容可以參考部落格《五大常用演算法》)

排序演算法:我的部落格已經做出了總結,看《資料結構中常用的排序演算法》。

二叉樹相關演算法

鍊錶相關演算法

雜湊表相關演算法

學習思路 --- 先了解基本的概念,然後找到相關的例題加以鞏固即可。

對於基本的概念先摘錄下來,知道大概的思想是什麼。 對於例題,盡量自己去思考和實踐,多實踐幾次就可以了。

學習任務: 今天7點之前對這些演算法的簡單題都會做即可。  後面做到了就好。 開始不要鑽牛角尖。 切記切記。效率最為重要。

注意:無論如何,看書入門都是最好的途徑。

學習方法: 看書,看書,看書! 千萬別學習新東西的時候就去看人的部落格。打好基礎!

正文

雜湊技術是在記錄的儲存位置和它的關鍵字之間建立乙個確定的對應關係f,使得每個關鍵字key對應乙個儲存位置f(key)。查詢時,根據這個確定的對應關係找到給定key的對映f(key),若找到了集合中存在這個記錄,那麼必定在f(key)的位置上。

我們把這種對應關係f稱為雜湊函式,又稱為雜湊函式,這塊連續儲存空間就稱為雜湊表或雜湊表。那麼關鍵字對應的記錄儲存位置我們稱為雜湊位址。

雜湊技術即使一種儲存方法也是一種查詢方法,它最適合的求解問題是查詢與給定值相等的記錄。 但是對於那種同樣的關鍵字有很多記錄的情況就不適合了。並且雜湊表也不適合範圍查詢。

在理想的情況下,不同的關鍵字通過雜湊函式(雜湊函式)計算得到的位址都是不同的。

但是現實中,很有可能兩個不同的關鍵字通過雜湊函式計算得到了相同的位址,這就是衝突。(即key1 !== key2 但是f(key1) === f(key2),這就是衝突了)

簡單的說雜湊函式,就是根據乙個關鍵字找到他的位址的函式。

想要知道有什麼構造方法,就得先確定乙個原則,怎麼樣構造得到的雜湊函式才是好的呢? 有下面的兩個原則:

1. 直接定址法

位址

出生年份

人數00 

1990

500萬

011991

520萬

021992

560萬

即位址就是出生年份這個關鍵字-1990,  然後就可以通過key很快的尋到位址了。

也就是說我們可以通過取關鍵字的某個線性函式為雜湊位址(f(key) = a x key + b),這種方法就是直接位址法

優點: 迅速、方便、不會產生衝突

缺點: 必須連續、 必須實現知道關鍵字的分布情況、只適合查詢表較小且連續的情況。

2. 數字分析法

數字分析法,把位數較多的數字作為關鍵字,如乙個公司的所有工作人員的登記表,每乙個人對應的一條記錄,由於手機號是不重複的,所以我們可以將手機號作為關鍵字,然後根據手機號來確定位址,由於前面7位重複的概率比較大,所以我們可以把後面的四位**號碼作為雜湊表的位址,這裡所做的就是抽取工作,當然也不可避免的會出現衝突。但是我們可以通過將衝突中的乙個的位址進行反轉、右環位移、甚至前兩位和後兩位疊加的方法避免衝突即可。

3. 平方取中法

即對於關鍵字1234,求得平方為1522756,取中間的三位227作為雜湊位址,這就是平方取中法。 這種方法適合於不知道關鍵字的分布,而位數又不是很大的情況。

4. 摺疊法

即將關鍵字從左到右分割成位數相等的幾部分(最後一部分不夠也沒關係), 然後將這幾部分疊加求和, 並按照雜湊表表長,取後幾位作為雜湊位址。

如關鍵字是9876543210,那麼我們可以將之分為3位,分成四組,987|654|321|0,然後疊加得到 987+654+321+0 = 1962,最後取後三位962作為雜湊表位址。

這種方法適合於事先不知道關鍵字的分布,適合關鍵字位數較多的情況。

5.除留餘數法

這種方法是最常用的構造雜湊函式(雜湊函式)的方法。 對於雜湊表長為m的雜湊函式公式為:

f(key) = key mod p (p<=m) 

注意,這裡選擇p小於等於m是有原因的,p選不好,也有可能造成衝突,根據前輩們的經驗,若雜湊表的表長為m,那通常p為小於或等於表長(最好接近m)的最小質數或不包含小於20質因子的合數。

6. 隨機數法

選擇乙個隨機數,取關鍵字的隨機函式為它的雜湊位址。 也就是f (key) = randow(key)。  

有同學問了,你說的關鍵字都是數字,如果關鍵字是字串怎麼辦?  ---可以轉換為ascii碼或者unicode碼啊。  

在構建雜湊表時,難免會有衝突,我們怎麼解決衝突呢? 這就是乙個問題了。

比如,你買房,已經看好了,準備交錢的時候發現房子已經給賣掉了,但你可以再換一家啊,是不是,只要還有房子就行。於是,開放位址法就是這樣的一種思路。

fi(key) = ( f(key) + di ) mod m (di = 1,2,3...m-1)

但是我們如果能讓它在兩邊找位置不是更好嗎? 於是新的規則如下:

fi(key) = ( f(key) + di ) mod m (di = 12,-12,22,-22...q2,-q2, q<= m/2)

這樣我們可以看到查詢的時候是雙向查詢的,並且不是連續查詢的,這就是二次探測法。好處是不讓關鍵字都聚集在某一塊區域,並提高了效率。

還有一種方法是隨機探測法, 這種犯法是產生乙個隨機數列,然後去查詢。

同樣以買房子為例,你之前看房子都在市中心,但市中心沒了(衝突了),你還可以去郊區看看啊。 

對於我們的雜湊表而言,我們實現準備多個雜湊函式。

fi(key) = rhi(key) (i=1,2....k)

其中rhi就是不同的雜湊函式,這些雜湊函式是用了什麼除留餘數、摺疊、平方取中都用了的。每當衝突產生時,我們就換乙個雜湊函式,總有不衝突的。

有衝突我也可以不走啊,直接將所有關鍵字為同義詞的記錄儲存在乙個單鏈表裡就可以了啊,我們稱之為同義詞子表。在雜湊表中只儲存所有同義詞子表的頭指標。 

鏈位址法對於可能會造成很多衝突的雜湊函式來說,提供了絕不會找不到位址的保障,但是在查詢時需要遍歷單鏈表,這會帶來效能損耗

這種方法更好理解,即你不是衝突嗎? 凡是因為衝突沒地去的都跟我走,即為所有衝突的關鍵字建立乙個公共的溢位區來存放。

在查詢時,對給定值通過雜湊函式計算出雜湊位址後,先與基本表的相應位置進行對比,如果相等,則查詢成功;如果不等,則到溢位表中進行順序查詢。   如果相對於基本表而言,有衝突的資料很少的情況下,公共溢位區的結構對查詢效能來說還是非常高的。

首先需要定義乙個雜湊表的結構以及一些相關的常數。其中hashtable就是雜湊表結構。 結構中的elem是乙個動態陣列

#define success 1

#define unsuccess 0

#define hashsize 12

#define nullkey -32768typedef

struct

hashtable;

int m = 0;

已經有了hashtable的定義,我們就可以對這個雜湊表進行初始化了。

/*

初始化雜湊表

*/status inithashtable (hashtable *h)

return

ok;}

/*

雜湊函式

*/int hash(int

key)

初始化之後,我們可以對雜湊表進行插入操作。 假設我們插入的關鍵字集合就是前面的。

/*

插入關鍵字進入雜湊表(剛剛只是初始化了)

*/void inserthash(hashtable *h,int

key)

h->elem[addr] = key; /*

有空位就插入關鍵字

*/}

雜湊表存在之後,我們就可以在需要的時候通過雜湊表來查詢需要的記錄了。

/*

雜湊表查詢關鍵字

*/status searchhash(hashtable h,

int key, int *addr)

}return

success;

}

常用演算法總結

通過區域性盡可能達到最優 貪婪的名字由來 從而實現整體的最優,貪婪演算法不一定總是正確的,因為每個區域性最優並不代表整體最優,但是在某些時候,它是正確.例如 為了找出找出17美元61美分 用最少的紙幣 肯定是按照最大面額盡可能多得先找,然後依次,所以先找乙個10美元的,在找乙個5美元的,再找2個1美...

常用演算法總結

常用演算法總結 前言與準備工作 動態規劃演算法 貪心演算法 分治演算法 回溯法 分支限界法。此部分內容可以參考部落格 五大常用演算法 排序演算法 我的部落格已經做出了總結,看 資料結構中常用的排序演算法 二叉樹相關演算法 鍊錶相關演算法 雜湊表相關演算法 學習思路 先了解基本的概念,然後找到相關的例...

常用演算法總結

排序演算法穩定性的簡單形式化定義為 如果ai aj,排序前ai在aj之前,排序後ai還在aj之前,則稱這種排序演算法是穩定的。引用下網上的圖 1 氣泡排序 在要排序的一組數中,對當前還未排好序的範圍內的全部數,自上而下對相鄰的兩個數依次進行比較,讓較大的數往下沉,較小的往上冒。即 每當兩相鄰的數比較...