從兩個陣列中查詢相同的數字談Hashtable

2021-06-17 00:41:52 字數 2494 閱讀 4280

因為在不久的將來就要用到這個演算法,所以先存起來,等用的時候就不需要再找了

假設陣列a有n個元素,陣列b有n個元素。

看到這種題的時候,我們最直觀的就是通過兩層for迴圈來對比每個陣列中的數字。因此a陣列中的每個元素都會和b陣列中的每個元素對比過一次,所以總共要對比的次數是n個n相加(或者是n個m相加),也就是n2(或者為n x m).

因此我們想能不能有更快的方法呢?讓其中乙個陣列的查詢的時間複雜度不再是o(n)就可以了。也就是我們在這個陣列中查詢乙個數,不是通過遍歷的方式。

但是不是通過遍歷的方式能在乙個陣列中找到乙個自己想要的數嗎?看起來必須有什麼特殊的方法才行。

我們再回過頭來看陣列是什麼組成的:

1.下標

2.下標所代表的元素

我們按位置查詢時,陣列的速度是o(1)的,因為我們只需要通過下標就可以定位那個元素。否則需要採用遍歷的o(n)的方式。

o(n)看起來好像速度還可以,其實想想看還真沒有比它更慢的了,你都把遍歷完一遍了當然知道有沒有所需要的元素了。

這時,我們就想到,如果用下標位置來標示所需的數字呢,而元素用來標記是否出現,出現1次就加1。比如說陣列a中存在元素12,就在由陣列b轉換後的陣列c中檢查c[12]是否等於1.

我們把陣列b轉換成陣列c,所需要的時間也為o(n)

那就使得對a陣列的遍歷仍為o(n),但檢查陣列a中的元素是否存在於陣列c中則由原來的o(n)轉換為o(1).

所以總的時間複雜度為o(n+n)。

看起來不錯,但是問題來了,如果a中的數字很大並且很分散時,會造成陣列c中大量的空間被浪費。比如說陣列a是由這三個元素,那麼輔助陣列c就需要667的大小,但是只用到了其中的3個,也就是664個空間是白浪費的。

這種直接通過陣列下標定址的方法,在陣列元素非連續的情況下,會造成大量空間浪費。

那什麼情況下陣列中的數字會比較連續呢?還記得這張圖吧,不記得的點這裡:

也就是ascii碼。

所以這種方式除了用來查詢數字,也可以用來查詢字母

**如下:(趕時髦用c來寫,寫的過程中感覺各種不適應啊。注:"abc"是作為指標傳遞,'abc'是作為整數傳遞,陣列在作為引數時會退化為指標。)

#include #include char * findsamechar(char *stringa, char *stringb)

const

int containersize = 128;

unsigned int container[containersize];

for (unsigned int i=0; i0;

}char *result = (char *)malloc(sizeof(stringa));

char *key = stringa;

while(*key != '

\0')

container[*(key++)]++;

key = stringb;

char *findresult = result;

while(*key != '

\0')

key++;

}if (result != null)

return result;

else

return'\0

';}

空間複雜度為o(1),因為這裡我開的輔助記憶體大小為128是個常數。

這種下標和數字緊耦合的方式使得我們這種方法受到了極大的限制,那麼我們有沒有辦法「解耦」呢?

也就是說,讓1,和666不要離開這麼遠,中間空了665個空位。讓他們盡可能的靠近些。這時候就需要通過一種方法來實現這種解耦,也就是說通過某個函式算出相應的位置,使得1和666之間的空格數盡量更小。

這就是hash函式。

hash技術很好的解決了直接定址遇到的問題,但是這麼做同時也引入了新的問題,通過hash函式算出來的位置可能會相同,一般就稱為發生了「碰撞"。也就是雖然我們希望通過hash函式使得1和666的位置盡量能靠近些,但是可能某些hash函式算出來的結果就是1和666位置相同。一般發生這種情況有幾種方式解決,二次hash和鏈結法。鏈結法用的是最多的,就是在同乙個位置上建立乙個鍊錶。

當然如果碰撞多了,hash表也變成了鏈結構,會極大的影響效率。當初某個bug就是因為採用了某種hash演算法導致產生大量的碰撞,使得伺服器效能下降。

hash錶用的地方非常多,比如資料庫中就是用了雜湊表,通常採用的是除法hash方式。

在用來設計雜湊函式的除法雜湊法中,通過取k除以m的餘數,來將關鍵字k對映到m個位置中的某個位置,也就是:

hash(k) = k mod m;

順便值得一提的是,獲取餘數是個經常用到的方法,比如說兩人跑步套圈,迷宮中的右手扶牆演算法等。也就是說能讓乙個數不停的在乙個指定的範圍內打轉。

.net中相應的實現是hashset,dictionary,hashtable。

當然這幾種結構肯定有區別,下篇還要談談equals和gethashcode再說吧。

查詢兩個陣列相同元素

攢rp ing 一場面試的一道演算法題,題目如下 有兩個公升序的陣列,在這兩個陣列裡面有且只有乙個相同的元素,考慮時間和空間複雜度,找到該元素,禁用js中所有方法,單純演算法題 emmmmm,為何和我之前的不一樣 話不多說,上 我真是越來越喜歡動手敲一下了 function foo arr 1,ar...

判斷兩個陣列中是否存在相同的數字

有2個陣列.裡面有n個整數,設計乙個演算法o nlog2 n 看是否兩個陣列裡存在同乙個數 1 思路 把這個陣列放在乙個陣列中排序,然後遍歷一邊陣列就可以判斷,缺點需要額外的空間支援 include includevoid quicksort int s,int start,int end retu...

兩個 陣列,需要挑出相同的元素

一般的 首先肯定會想到 這樣的程式 for int i 0 ifor int j 0 i.但是這裡需要注意的就是 這個方法需要迴圈 m n 次才可以 完成此任務。所以考慮使用雜湊表的方法,將乙個陣列裝入雜湊表中,然後判斷另乙個陣列是否存在表內即可。這種方法的迴圈次數是m n.例如 public st...