資料結構的學習已經接近尾聲了,最後我學習了雜湊表的一些相關知識,了解了源**的大致框架,在最後模擬實現一次雜湊桶,這是乙個比較考驗**能力的練習,也算是一次自我挑戰吧。
雜湊演算法就是給定引數的值通過乙個雜湊函式對映乙個陣列中的位置,然後將該引數存入雜湊表。由於存在一對一對映關係,這種儲存方式的查詢已經儲存的東西是最快的。但是由於雜湊函式一般不會給出連續的空間,因此消耗的空間也較之前的儲存方式更多(很多閒置的空間),所以這是一種典型的空間換時間交換時間的演算法。
但是,不同的引數有時候會對映到同乙個位置上,這種問題被稱為雜湊衝突,解決雜湊衝突的演算法很多,其中常用的方法有線性探測,二次探測和雜湊桶等。我們要實現乙個用雜湊桶解決雜湊衝突的雜湊表(盡量和stl保持一致)。
雜湊桶就是當不將引數直接存入陣列中,而是在陣列中放置乙個節點指標,當對映在陣列對應的位置時,new乙個節點空間,將該節點「掛」到這個指標陣列的對應指標下面,如果再衝突,就再掛到下面。腦海裡就是乙個陣列+鍊錶的儲存方式。結構和演算法就是這樣接下來話不多說,放碼過來。
#include #include #include #include using namespace std;
templatestruct hashnode //雜湊節點
hashnode(const v& valuefield)
:_valuefield(valuefield), _next(null)
{}};
template < class k, class v, class keyofvalue,class _hashfunc>
class hashtable;
template//雜湊函式
struct __hashfunc
};template<>
struct __hashfunc//string物件經常被儲存,因此在這裡順便實現。
return (hash & 0x7fffffff);
} size_t operator()(const string& s, const size_t size) };
templatestruct _keyofvalue //實現keyofvalue是因為我們往節點裡存的不一定是乙個值,但是我們用來對映到陣列的某個位置時,卻只需要乙個值,這個仿函式要做的
//就是告訴我們到底需要哪個值
};templatestruct _pairkeyofvalue
};templatestruct hashtableiterator//迭代器
hashtableiterator(node* node, _table* tb)
:_node(node), _tb(tb)
{} node& operator*()const
node* operator->()const
bool operator!=(const iterator& it)const
iterator& operator++()
return *this;
} node* _node;
_table* _tb;
};template < class k, class v, class keyofvalue = _keyofvalue, class _hashfunc = __hashfunc >
class hashtable
~hashtable()
node* find(const k& key)
return cur;
} iterator begin()
return iterator(cur, this);
} iterator end()
bool insert(const valuetype& valufield)//插入
else
} size_t size()
bool remove(const k& key)//刪除
if (keyofvalue(cur->_valuefield)== key)
else
}return false;
} }protected:
void destory()
}} void checkcapcity()
}_table.swap(newtable);
} }protected:
vector_table;
size_t _size;
};void testhashtable()
*/ t.insert(1);
t.insert(2);
t.insert(11);
/*t.remove(1);
t.remove(2);
t.remove(11);
t.remove(13);*/
hashtable::iterator it = t.begin();
while (it != t.end())
cout <, _pairkeyofvalue> t1;
t1.insert(make_pair("lizi", 1));
t1.insert(make_pair("xiangjiao", 3));
t1.insert(make_pair("taozi", 6));
t1.insert(make_pair("pingguo", 55));
/*t1.remove(5);
t1.remove(5);
t1.remove(5);
t1.remove(55);*/
//cout << t.find(2) << endl;
hashtable, _pairkeyofvalue> ::iterator it1 = t1.begin();
while (it1 != t1.end())
cout << endl;
}
雜湊表有乙個負載因子,用來控制空間的分配(當資料存放多到什麼時候應該增容),負載因子=允許負載的最大節點數/當前陣列空間的大小,細心的訪客已經看到了,我這個雜湊表的負載因子為1.負載因子的選取是雜湊表效能的關鍵,太大了會導致衝突變多,太小了會導致空間浪費嚴重。
也許有人不明白為什麼要這樣寫,這樣使用起來很麻煩啊。答案是你們說的沒錯,就是很麻煩,但是我們這樣寫全部是為了**復用性好。可能大家不熟悉,在stl中,unordered_map和unordered_set其實原型都是這個雜湊桶,只是在這上層做了乙個簡單的封裝,就可以將兩個容器的**,共用乙個模板,舉個例子,我們使用unordered_set(乙個模板引數)時,將模板的key和value都使用成乙個型別如上圖中的hashtable,即為unordered_set(將兩個模板引數傳成相同的),而我們使用unordered_map時,只是將模板改變一下變為hashtable>即可,這樣設計是不是很省事的就將乙份**完成了兩份工作呢?只是可能這樣子設計一開始會讓我們想窺探原始碼的人看的頭皮發麻,但是當我們搞清楚這樣設計的目的,再返回來看stl的源**,就可以理解其中蘊含的高深的思想。(經常使用的map和set也是這樣設計的哦,不過底層結構是紅黑樹而已)。
當然,雜湊表也是有缺陷的,在極端情況下,如果資料就是『』不聽話『』,一直衝突在某乙個位置,這樣還是會導致空間浪費嚴重, 並且時間複雜度也不再是o(1),因此還有擴充套件,當雜湊桶的某個指標下的節點長度大於一定程度時,不再是鏈式儲存,而轉換為紅黑樹(一種平衡搜尋樹),就可以有效解決這種問題。
Google Hacking 的實現以及應用 轉
前言 google hacking其實並算不上什麼新東西,在早幾年我在一些國外站點上就看見過相關的介紹,但是由於當時並沒有重視這種技術,認為最多就只是用來找找未改名的mdb或者別人留下的webshell什麼的,並無太大實際用途.但是前段時間仔細啃了些資料才猛然發覺google hacking其實並非...
google hacking的實現以及應用
google hacking其實並算不上什麼新東西,在早幾年我在一些國外站點上就看見過相關的介紹,但是由於當時並沒有重視這種技術,認為最多就只是用來找找未改名 的mdb或者別人留下的webshell什麼的,並無太大實際用途.但是前段時間仔細啃了些資料才猛然發覺google hacking其實並非如此...
Google Hacking的實現以及應用
google hacking其實並算不上什麼新東西,在早幾年我在一些國外站點上就看見過相關的介紹,但是由於當時並沒有重視這種技術,認為最多就只是用來找找未改名的mdb或者別人留下的webshell什麼的,並無太大實際用途.但是前段時間仔細啃了些資料才猛然發覺google hacking其實並非如此簡...