建立网站目录结构应遵循的方法和建议seo怎么优化步骤
1.前期准备与框架搭建
第一步:将哈希表(链地址法)的头文件加进项目,然后创建两个头文件Unordered_Map和Unorderd_Set。
第二步:unordered_set框架与unordered_map框架搭建
unordered_set:
#pragma once #include"hashtable.h" namespace myself {template<class K, class V>class unordered_map{public:private:HashTable<K, pair<K, V>> _ht;}; }
unordered_map:
#pragma once #include"hashtable.h" namespace myself {template<class K>class unordered_set{public:private:HashTable<K, K> _ht;}; }
这里我们传给哈希表的参数不再是key和value,而是单独的k和容器存储的数据类型(set中是key,map中是pair<K,V>),这样可以兼容set和map进哈希表
1.1支持insert
(1)解决find和erase中需要key查找,而哈希表中不确定存储数据类型是key还是key_value的问题
解法:使用仿函数KeyOfT,仿函数作用是返回容器的key值引用
首先我们要在unordered_set中写一个SetOfT,返回值类型为K,不过需要注意的是返回的是const类型的,否则会导致权限放大
struct SetOfT{const K& operator()(const K& key){return key;}};
然后是unordered_map
struct MapOfT{const K& operator()(const pair<K,V>& data){return data.first;}};
然后在哈希表中加一个模板参数KeyOfT,用于接收unordered_set和unordered_map的仿函数
(2)将key类型转换为可以进行取模运算的类型
解法:使用仿函数Func,对于特殊类型如string就进行类模板特化
template<class K> struct HashFunc {size_t operator()(const K& key){return (size_t)key;} };
使用struct是因为这个仿函数是需要哈希表可以直接调用的,所以用struct就可以默认开放给类外面
(3)更改哈希表中的insert
bool Insert(const T& data){KeyOfT kot;Func fc;//不允许冗余if (Find(kot(data))) return false;//负载因子为1就扩容if (_n == _tables.size()){vector<Node*> newtable (2 * _tables.size());for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){//将旧的表中节点挪到新表中Node* next = cur->_next;size_t hash0 = fc(kot(cur->_data)) % newtable.size();//头插cur->_next = newtable[hash0];newtable[hash0] = cur;//更新curcur = next;}_tables[i] = nullptr;}newtable.swap(_tables);}//头插size_t hash0 = fc(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hash0];_tables[hash0] = newnode;_n++;return true;}
1.只有需要使用key的情况我们才用kot将key取出来,如果就是要使用容器存储的数据类型,比如节点构造,那么我们就需要直接用data
2.func主要用于进行取模运算的时候,此时需要key是一个可以取模运算的数据类型
(4)更改Find与Erase
Node* Find(const K& key){Func fc;KeyOfT kot;size_t hash0 = fc(key) % _tables.size();Node* cur = _tables[hash0];while (cur){if (kot(cur->_data) == key) return cur;cur = cur->_next;}return nullptr;}bool Erase(const K& key){KeyOfT kot;Func fc;size_t hash0 = fc(key) % _tables.size();Node* cur = _tables[hash0];Node* prv = nullptr;while (cur){if (kot(cur->_data) == key)//delete{if (prv == nullptr){_tables[hash0] = cur->_next;}else{prv->_next = cur->_next;}delete cur;--_n;return true;}prv = cur;cur = cur->_next;}return false;}
(5)实现析构
~HashTable(){for (size_t i = 0; i < _tables.size(); i++){ //逐个桶进行释放Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}
1.2支持iterator
//哈希表前置声明template<class K, class T, class KeyOfT, class Func >class HashTable;//迭代器实现template<class K, class T, class KeyOfT, class Func >struct HTIterator{typedef HashTable<K, T, KeyOfT, Func> HT;typedef HashNode<T> Node;typedef HTIterator<K, T, KeyOfT, Func> self;//迭代器存储内容HT* _ht;Node* _node;//构造HTIterator(Node* node,HT* ht):_ht(ht),_node(node){}//运算符重载T* operator->(){return &(_node->_data);}T& operator*(){return _node->_data;}self& operator++(){Func fc;KeyOfT kot;//当前桶没走完Node* cur = _node;if (cur->_next){_node = _node->_next; }else//当前桶走完了,寻找下一个桶的头结点{size_t hashi = fc(kot(_node->_data)) % _ht->_tables.size();hashi++;while (hashi < _ht->_tables.size())//没有走完哈希表{if (_ht->_tables[hashi]){_node = _ht->_tables[hashi];break;}hashi++;}if (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}bool operator!=(const self& s){return _node != s._node;}bool operator ==(const self& s){return _node == s._node;}};
1.模板参数的缺省参数只能给一次,不能在多个地方重复给,这样会可能导致缺省参数混乱,所以在语法层面禁止了
2.需要在迭代器前面前置声明一下HashTable,告诉编译器他是一个类
3.迭代器++的逻辑:
(1)当前桶没有走完,那么就直接让迭代器指向下一个node,然后返回迭代器
(2)当前桶走完了,需要寻找下一个有数据的桶,若找到了就指向新桶的第一个数据,没有找到就指向nullptr。
最后返回迭代器本身
4.由于迭代器++的逻辑中使用了哈希表的private成员变量,所以我们需要让迭代器成为哈希表的友元函数
接下来我们实现哈希表中的迭代器
//实现begin和endIterator Begin(){//找第一个节点for (size_t i = 0; i < _tables.size(); i++){if (_tables[i]){return Iterator(_tables[i], this);}}return End();}Iterator End(){return Iterator(nullptr,this);}
begin:寻找哈希表中第一个节点,然后用该节点地址和哈希表本身地址构造迭代器
end:我们以nullptr表示没有节点了,所以用nullptr和哈希表本身地址构造迭代器
然后我们对unordered_set和unordered_map进行封装迭代器
注意要写在public修饰符内部
unordered_set:
typedef typename HashTable<K, K, SetOfT>::Iterator iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}
unordered_map:
typedef typename HashTable<K, pair<K, V>, MapOfT>::Iterator iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}
1.3支持const_iterator
支持const迭代器我们只需要在迭代器的模板参数中增加两个参数,Ref和Ptr即可,因为增加他们就可以控制运算符->和*的返回值类型
//迭代器实现template<class K, class T, class Ref, class Ptr,class KeyOfT, class Func >struct HTIterator{typedef HashTable<K, T, KeyOfT, Func> HT;typedef HashNode<T> Node;typedef HTIterator<K, T,Ref,Ptr,KeyOfT, Func> self;//迭代器存储内容const HT* _ht;Node* _node;//构造HTIterator(Node* node,const HT* ht):_ht(ht),_node(node){}//运算符重载Ptr operator->(){return &(_node->_data);}Ref operator*(){return _node->_data;}self& operator++(){Func fc;KeyOfT kot;//当前桶没走完Node* cur = _node;if (cur->_next){_node = _node->_next; }else//当前桶走完了,寻找下一个桶的头结点{size_t hashi = fc(kot(_node->_data)) % _ht->_tables.size();hashi++;while (hashi < _ht->_tables.size())//没有走完哈希表{if (_ht->_tables[hashi]){_node = _ht->_tables[hashi];break;}hashi++;}if (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}bool operator!=(const self& s){return _node != s._node;}bool operator ==(const self& s){return _node == s._node;}};
注意:这里我们修改了构造函数的参数,将HT*变为const属性,这是因为后续支持cosnt_iterator的时候会传递的对象是const属性,如果这里参数不是const属性会导致权限被放大。且这里我们即使加上了const也不会影响迭代器逻辑,因为迭代器中没有修改哈希表的部分
然后我们通过控制模板参数重命名一个const迭代器,并对unordered_set和unordered_map套上const迭代器
(1)在HashTable加上const迭代器
template<class K, class T, class KeyOfT,class Func = HashFunc<K>> class HashTable {//友元声明template<class K, class T,class Ref,class Ptr ,class KeyOfT, class Func >friend struct HTIterator;typedef HashNode<T> Node; public:typedef HTIterator<K, T,T&,T*,KeyOfT, Func> Iterator;typedef HTIterator<K, T, const T&, const T*, KeyOfT, Func> Const_Iterator;HashTable(size_t size = 53):_tables(size, nullptr),_n(0){}//实现begin和endIterator Begin(){//找第一个节点for (size_t i = 0; i < _tables.size(); i++){if (_tables[i]){return Iterator(_tables[i], this);}}return End();}Iterator End(){return Iterator(nullptr,this);}//实现const的begin和endConst_Iterator Begin() const{//找第一个节点for (size_t i = 0; i < _tables.size(); i++){if (_tables[i]){return Const_Iterator(_tables[i], this);}}return End();}Const_Iterator End() const{return Const_Iterator(nullptr, this);}bool Insert(const T& data){KeyOfT kot;Func fc;//不允许冗余if (Find(kot(data))) return false;//负载因子为1就扩容if (_n == _tables.size()){vector<Node*> newtable (2 * _tables.size());for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){//将旧的表中节点挪到新表中Node* next = cur->_next;size_t hash0 = fc(kot(cur->_data)) % newtable.size();//头插cur->_next = newtable[hash0];newtable[hash0] = cur;//更新curcur = next;}_tables[i] = nullptr;}newtable.swap(_tables);}//头插size_t hash0 = fc(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hash0];_tables[hash0] = newnode;_n++;return true;}
(2)给unordered_set和unordered_map加上const迭代器
unordered_map:
typedef typename HashTable<K, pair<K, V>, MapOfT>::Iterator iterator;typedef typename HashTable<K, pair<K, V>, MapOfT>::Const_Iterator const_iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}
unordered_set:
typedef typename HashTable<K, K, SetOfT>::Iterator iterator;typedef typename HashTable<K, K, SetOfT>::Const_Iterator const_iterator;const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}
1.4将key现在可以修改的情况改为不可修改
只需要在unordered_set和unordered_map中把容器存储类型中的key变为const属性即可
在private部分,typedef部分修改
typedef typename HashTable<K, const K, SetOfT>::Iterator iterator;typedef typename HashTable<K, const K, SetOfT>::Const_Iterator const_iterator;const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}bool insert(const K& key){return _ht.Insert(key);}void print(const unordered_set<int>& s){const_iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;}void testset(){unordered_set<int> s;s.insert(1);s.insert(2);print(s);}private:HashTable<K, const K,SetOfT> _ht;
typedef typename HashTable<K, pair<const K, V>, MapOfT>::Iterator iterator;typedef typename HashTable<K, pair<const K, V>, MapOfT>::Const_Iterator const_iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}bool insert(const pair<const K,V>& kv){return _ht.Insert(kv);}private:HashTable<K, pair<const K, V>,MapOfT> _ht;};
1.5实现operator[]
operator[]的实现依赖于insert,而我们现在的insert还不是最终版本,接下来我们进行修改
第一步:修改Find()
Iterator Find(const K& key){Func fc;KeyOfT kot;size_t hash0 = fc(key) % _tables.size();Node* cur = _tables[hash0];while (cur){if (kot(cur->_data) == key) return {cur,nullptr};cur = cur->_next;}return End();}
若找到了就用当前的cur构建迭代器返回,没有找到就返回end迭代器
第二步:修改insert
pair<Iterator,bool> Insert(const T& data){KeyOfT kot;Func fc;//不允许冗余Iterator it = Find(kot(data));if (it != End()) return {it,false};//负载因子为1就扩容if (_n == _tables.size()){vector<Node*> newtable (2 * _tables.size());for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){//将旧的表中节点挪到新表中Node* next = cur->_next;size_t hash0 = fc(kot(cur->_data)) % newtable.size();//头插cur->_next = newtable[hash0];newtable[hash0] = cur;//更新curcur = next;}_tables[i] = nullptr;}newtable.swap(_tables);}//头插size_t hash0 = fc(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hash0];_tables[hash0] = newnode;_n++;return { {newnode,this},true };}
第三步:实现operatoar[]
V& operator[](const K& key){pair<iterator, bool> p = insert({ key,V() });return p.first->second;}
1.6在unordered_set和unordered_map中增加一个模板参数
增加一个Func参数,主要是方便我们写仿函数控制key的数据类型可以转换为可以取模的类型
unordered_map的控制:
template<class K, class V, class Func = HashFunc<K>>class unordered_map{struct MapOfT{const K& operator()(const pair<const K,V>& data){return data.first;}};
unordered_set的控制:
template<class K, class Func = HashFunc<K>>class unordered_set{struct SetOfT{const K& operator()(const K& key){return key;}};