演算法鍵值
① 求js對象鍵名根據鍵值排序,按排序順序產生新鍵名數組的高效演算法
constdata={1001:1,1002:3,1003:2,1004:2,1005:1};
constkeys=Object.keys(data);
keys.sort(function(a,b){
returndata[b]-data[a];});
console.log(keys);
['1002','1003','1004','1001','1005']
只是js對象的健是字元串,用的時候還要轉換一下
constout=keys.map(function(x){returnparseInt(x);});
console.log(out);
[1002,1003,1004,1001,1005]
② 哈希查找演算法
散列表(Hash table,也叫哈希表),是根據鍵(Key)而直接訪問在內存存儲位置的數據結構。也就是說,它通過計算一個關於鍵值的函數,將所需查詢的數據映射到表中一個位置來訪問記錄,這加快了查找速度。這個映射函數稱做散列函數,存放記錄的數組稱做散列表。
通過某種轉換關系,使關鍵字適度的分散到指定大小的的順序結構中,越分散,則以後查找的時間復雜度越小,空間復雜度越高。
Hash是一種典型以空間換時間的演算法,比如原來一個長度為100的數組,對其查找,只需要遍歷且匹配相應記錄即可,從空間復雜度上來看,假如數組存儲的是byte類型數據,那麼該數組佔用100byte空間。現在我們採用Hash演算法,我們前面說的Hash必須有一個規則,約束鍵與存儲位置的關系,那麼就需要一個固定長度的hash表,此時,仍然是100byte的數組,假設我們需要的100byte用來記錄鍵與位置的關系,那麼總的空間為200byte,而且用於記錄規則的表大小會根據規則,大小可能是不定的。
通過哈希函數,我們可以將鍵轉換為數組的索引(0-M-1),但是對於兩個或者多個鍵具有相同索引值的情況,我們需要有一種方法來處理這種沖突。
一種比較直接的辦法就是,將大小為M 的數組的每一個元素指向一個鏈表,鏈表中的每一個節點都存儲散列值為該索引的鍵值對,這就是拉鏈法。下圖很清楚的描述了什麼是拉鏈法。
「John Smith」和「Sandra Dee」 通過哈希函數都指向了152 這個索引,該索引又指向了一個鏈表, 在鏈表中依次存儲了這兩個字元串。
單獨鏈表法:將散列到同一個存儲位置的所有元素保存在一個鏈表中(聚集),該方法的基本思想就是選擇足夠大的M,使得所有的鏈表都盡可能的短小,以保證查找的效率。當鏈表過長、大量的鍵都會映射到相同的索引上,哈希表的順序查找會轉變為鏈表的查找,查找時間將會變大。對於開放定址會造成性能的災難性損失。
實現基於拉鏈表的散列表,目標是選擇適當的數組大小M,使得既不會因為空鏈表而浪費內存空間,也不會因為鏈表太而在查找上浪費太多時間。拉鏈表的優點在於,這種數組大小M的選擇不是關鍵性的,如果存入的鍵多於預期,那麼查找的時間只會比選擇更大的數組稍長。另外,我們也可以使用更高效的結構來代替鏈表存儲。如果存入的鍵少於預期,索然有些浪費空間,但是查找速度就會很快。所以當內存不緊張時,我們可以選擇足夠大的M,可以使得查找時間變為常數,如果內存緊張時,選擇盡量大的M仍能夠將性能提高M倍。
線性探測法是開放定址法解決哈希沖突的一種方法,基本原理為,使用大小為M的數組來保存N個鍵值對,其中M>N,我們需要使用數組中的空位解決碰撞沖突。如下圖所示:
對照前面的拉鏈法,在該圖中,「Ted Baker」 是有唯一的哈希值153的,但是由於153被「Sandra Dee」佔用了。而原先「Snadra Dee」和「John Smith」的哈希值都是152的,但是在對「Sandra Dee」進行哈希的時候發現152已經被佔用了,所以往下找發現153沒有被佔用,所以索引加1 把「Sandra Dee」存放在沒有被佔用的153上,然後想把「Ted Baker」哈希到153上,發現已經被佔用了,所以往下找,發現154沒有被佔用,所以值存到了154上。
單純論查找復雜度:對於無沖突的Hash表而言,查找復雜度為O(1)。
原文: 哈希查找 - 賣賈筆的小男孩 - 博客園 (cnblogs.com)