当前位置: 首页 > wzjs >正文

富阳网站建站公司哪家好淘宝购物

富阳网站建站公司哪家好,淘宝购物,常州做网站的公司,免费的logo在线设计一、unordered系列容器 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到logN,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很…

一、unordered系列容器

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到logN,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到。在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。

unordered_xxx系列与map和set容器的用法上几乎没有任何区别

他们的区别就是

unordered_xxx系列都是哈希表作为底层的,而map和set是用红黑树作为底层的
unordered_xxx系列不排序,只去重
unordered_xxx系列是单项迭代器

二、unordered_set

如下就是unordered_set的文档

unordered_set是一种容器,它以无特定顺序的方式存储唯一的元素,并允许根据元素的值快速检索各个元素。

在unordered_set中,元素的值同时也是它的键,唯一标识该元素。键是不可变的,因此,unordered_set中的元素一旦放入容器后就不能被修改,不过可以插入和删除。

在内部,unordered_set中的元素不按任何特定顺序排序,而是根据它们的哈希值组织成桶,以便通过它们的值(平均具有恒定的平均时间复杂度)直接快速访问各个元素。

对于通过键访问单个元素,unordered_set容器比set容器更快,尽管对于通过子集范围迭代它们通常效率较低。

容器中的迭代器是单向迭代器。

这些接口其实大差不差

void test1()
{unordered_set<int> us;us.insert(7);us.insert(5);us.insert(4);us.insert(3);us.insert(1);us.insert(6);unordered_set<int>::iterator usit = us.begin();while (usit != us.end()){cout << *usit << endl;usit++;}
}

我们可以自己试着用一用

三、unordered_map

如下是unordered_map的文档

 unordered_map 是关联容器,用于存储由键值映射值组合形成的元素,并允许根据各个元素的键快速检索各个元素。
在 unordered_map 中,键值通常用于唯一标识元素,而映射值是具有与此关联的内容的对象。映射值的类型可能不同。
在内部,unordered_map中的元素不是根据其值或映射值按任何特定顺序排序的,而是根据其哈希值组织到中,以允许直接通过其键值快速访问各个元素(平均平均时间复杂度保持不变)。
unordered_map 容器通过访问单个元素的速度比 map 容器更快,尽管它们通常对其元素子集进行范围迭代的效率较低。
 unordered_map实现直接访问运算符 (operator[]),它允许使用其键值作为参数直接访问映射值
容器中的迭代器至少是单向迭代器。

我们可以试着用一用

void test2()
{unordered_map<string, string> dict;dict["insert"] = "插入";dict["sort"] = "排序";dict["delete"] = "删除";dict["string"] = "字符串";dict["insert"] = "xxxxx";dict.insert(make_pair("iterator", "迭代器"));unordered_map<string, string>::iterator umit = dict.begin();while (umit != dict.end()){cout << umit->first << ":" << umit->second << endl;umit++;}cout << endl;
}

四、unordered_set与set的比较

如下所示,我们采用如下代码进行比较

void test3()
{const size_t N = 100000;unordered_set<int> us;set<int> s;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; ++i){v.push_back(rand());//v.push_back(rand()+rand());  //减少重复数据//v.push_back(i);		  //有序的时候}size_t begin1 = clock();for (auto e : v){s.insert(e);}size_t end1 = clock();cout << "set insert:" << end1 - begin1 << endl;size_t begin2 = clock();for (auto e : v){us.insert(e);}size_t end2 = clock();cout << "unordered_set insert:" << end2 - begin2 << endl;size_t begin3 = clock();for (auto e : v){s.find(e);}size_t end3 = clock();cout << "set find:" << end3 - begin3 << endl;size_t begin4 = clock();for (auto e : v){us.find(e);}size_t end4 = clock();cout << "unordered_set find:" << end4 - begin4 << endl << endl;cout <<"插入数据个数:"<< s.size() << endl;cout <<"插入数据个数:" << us.size() << endl << endl;;size_t begin5 = clock();for (auto e : v){s.erase(e);}size_t end5 = clock();cout << "set erase:" << end5 - begin5 << endl;size_t begin6 = clock();for (auto e : v){us.erase(e);}size_t end6 = clock();cout << "unordered_set erase:" << end6 - begin6 << endl << endl;
}

可以看到,在无序的数据的时候,unordered_set更占优势一些。

但是我们会发现有很多的重复数据,于是我们可以对随机值+随机值以此减少重复数据

可以看到,还是unordered_set占据优势

在有序的数据时,此时set占据优势

因此,如果数据是无序的,unordered_set更优,如果是有序的,使用set更好

五、哈希与各种查找的比较

1.直接查找

就是我们最常见的暴力查找,他的时间复杂度是O(N)

2.二分

不过我们可以对其进行一定程度的优化,即先排序,这样的画他的时间复杂度就变为了logN,但是增删还是不方便,而且排序也需要时间。

3.平衡树

再后来就是使用红黑树,他的效率都是很优秀的,增删查改都是logN

4.哈希

即存储的值和存储位置建立出一个对应关系,这样的话时间复杂度直接变为了O(1),哈希我们也称作散列,哈希的方式有点类似于计数排序

5.STL中的哈希

STL库中,set类和map类都是红黑树作为底层实现的,与之类似,unordered系列的unordered_set类和unordered_map类,都是通过哈希表作为底层来实现的。

六、哈希表的修改

下面是我们之前写的哈希表

namespace hash_bucket
{template<class K,class V>struct HashNode{pair<K, V> _kv;HashNode<K, V>* _next = nullptr;HashNode(const pair<K, V>& kv):_kv(kv){}};template<class K>struct DefaultHashFunc{size_t operator()(const K& key){return (size_t)key;}};template<>struct DefaultHashFunc<string>{size_t operator()(const string& str){size_t hashi = 0;for (auto ch : str){hashi = hashi * 131 + ch;}return hashi;}};template<class K, class V, class HashFunc = DefaultHashFunc<K>>class HashTable{typedef HashNode<K,V> Node;public:HashTable():_n(0){_table.resize(10, nullptr);}bool Insert(const pair<K, V>& kv){if (Find(kv.first)){return false;}HashFunc hf;if (_n == _table.size()){size_t newSize = _table.size() * 2;vector<Node*> newTable(newSize, nullptr);for (int i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;size_t hashi = hf(cur->_kv.first) % newTable.size();cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}_table[i] = nullptr;}_table.swap(newTable);}size_t hashi = hf(kv.first) % _table.size();Node* newnode = new Node(kv);newnode->_next = _table[hashi];_table[hashi] = newnode;++_n;return true;}void Print(){for (int i = 0; i < _table.size(); i++){Node* cur = _table[i];printf("[%d]->", i);while (cur){cout << cur->_kv.first << ":" << cur->_kv.second << "->";cur = cur->_next;}cout << "NULL" << endl;}}Node* Find(const K& key){HashFunc hf;size_t hashi = hf(key) % _table.size();Node* cur = _table[hashi];while (cur){if (cur->_kv.first == key){return cur;}cur = cur->_next;}return nullptr;}bool Erase(const K& key){HashFunc hf;size_t hashi = hf(key) % _table.size();Node* cur = _table[hashi];Node* prev = nullptr;while (cur){if (cur->_kv.first == key){if (prev){prev->_next = cur->_next;}else{_table[hashi] = cur->_next;}delete cur;cur = nullptr;_n--;return true;}else{prev = cur;cur = cur->_next;}}return false;}~HashTable(){for (int i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_table[i] = nullptr;}}private:vector<Node*> _table;size_t _n;};
}

现在我们需要为了把它改装成unordered系列容器

1.结点

template<class T>
struct HashNode
{HashNode<T>* _next;T _data;HashNode(const T& data): _next(nullptr), _data(data){}
};

对于哈希表的修改与之前我们用红黑树去封装map和set类似。

首先是将结点都改为T类型的,这个T类型对于set而言是K,对于map而言是pair<K,V>
 

2.迭代器

改造后的哈希表,最重要的功能之一就是支持单向迭代器
 

template<class K, class T, class KeyOfT, class Hash>
class HashTable;//前置声明template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct HashIterator
{typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> Ht;typedef HashIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;typedef HashIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;Node* _node;const Ht* _ht;HashIterator(Node* node, const Ht* ht): _node(node), _ht(ht){}HashIterator(const Iterator& it): _node(it._node), _ht(it._ht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &(operator*());}bool operator!=(const Self& s){return _node != s._node;}bool operator==(const Self& s){return _node == s._node;}
};
  1. 这里增加_ht成员变量,这样当一条单链表走到空,可以走到下一个哈希桶的位置,所以需要哈希表的地址
  2. 这里存在相互引用的问题,所以前置声明哈希表
  3. const修饰_ht,使const迭代器能够被构造
  4. 迭代器的拷贝构造函数有两个用途:
    • 以普通迭代器拷贝出普通迭代器(普通迭代器调用时)
    • 以普通迭代器拷贝出const迭代器(const迭代器调用时)

3.operator++

Self& operator++()
{if (_node->_next){_node = _node->_next;}else{int flag = 0;size_t hashi = Hash()(KeyOfT()(_node->_data)) % _ht->_tables.size();for (size_t i = hashi + 1; i < _ht->_tables.size(); ++i){if (_ht->_tables[i]){_node = _ht->_tables[i];flag = 1;break;}}if (!flag){_node = nullptr;}}return *this;
}Self operator++(int)
{Self tmp = *this;++*this;return tmp;
}
  1. 前置++的思路:
    • 下一个结点不为空,则跳到下一位
    • 下一个结点为空,则先取模算出哈希地址,再往后探测不为空的哈希桶
  2. 后置++:复用前置++,返回临时对象

4.本体

1.成员变量和默认成员函数

template<class K, class T, class KeyOfT, class Hash>
class HashTable
{template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct HashIterator;
protected:typedef HashNode<T> Node;
public:HashTable(){_tables.resize(10);}~HashTable(){for (auto& cur : _tables){while (cur){Node* del = cur;cur = cur->_next;delete del;}}}
protected:vector<Node*> _tables;size_t _n = 0;//有效数据个数
};
  1. 将迭代器声明为友元,使迭代器内部可操作_tables
  2. 第三个模板参数为KeyOfT(仿函数),用于获取不同数据T的键值key来进行比较
  3. 第四个模板参数为Hash(仿函数),用于将不同类型key转换为整型来进行取模

2.begin和end

typedef HashIterator<K, T, T&, T*, KeyOfT, Hash> iterator;
typedef HashIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;iterator begin()
{for (size_t i = 0; i < _tables.size(); ++i){if (_tables[i]){return iterator(_tables[i], this);}}return iterator(nullptr, this);
}const_iterator begin() const
{for (size_t i = 0; i < _tables.size(); ++i){if (_tables[i]){return const_iterator(_tables[i], this);}}return const_iterator(nullptr, this);
}iterator end()
{return iterator(nullptr, this);
}const_iterator end() const
{return const_iterator(nullptr, this);
}
  1. begin返回最开始不为空的哈希桶的迭代器,end返回空迭代器
  2. 构造迭代器需要传入哈希表本身的地址,这里直接传this指针即可

3.Find

iterator Find(const K& key)
{size_t hashi = Hash()(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (KeyOfT()(cur->_data) == key){return iterator(cur, this);}cur = cur->_next;}return iterator(nullptr, this);
}

  1. 返回迭代器
  2. Hash转整型,KeyOfT获取键值

4.Insert

pair<iterator, bool> Insert(const T& data)
{KeyOfT kot;iterator it = Find(kot(data));if (it._node)//保持key唯一{return make_pair(it, false);}Hash hash;if (_n == _tables.size())//负载因子为1时,扩容{size_t newsize = _tables.size() * 2;vector<Node*> newtables(newsize);for (auto& cur : _tables){while (cur){Node* next = cur->_next;//将旧表结点重新映射到新表上size_t hashi = hash(kot(cur->_data)) % newsize;cur->_next = newtables[hashi];newtables[hashi] = cur;//跳回旧表的下一结点cur = next;}}_tables.swap(newtables);}size_t hashi = hash(kot(data)) % _tables.size();Node* newnode = new Node(data);//头插newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(iterator(newnode, this), true);
}
  1. 返回pair,第一个参数为迭代器,第二个参数为布尔值(记录是否插入成功)

5.Erase

bool Erase(const K& key)
{size_t hashi = Hash()(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (KeyOfT()(cur->_data) == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;--_n;return true;}prev = cur;cur = cur->_next;}return false;
}

5.unordered_set

1 成员变量与仿函数

template<class K, class Hash = HashFunc<K>>
class unordered_set
{struct SetKeyOfT{const K& operator()(const K& key){return key;}};
public:
protected:HashTable<K, K, SetKeyOfT, Hash> _ht;
};
  1. unordered_set类仿函数,直接返回参数key
  2. 成员变量的第二个模板参数为K,第三个模板参数为SetKeyOfT
  3. 模板Hash可以根据特定需要而传手动实现的哈希化函数

2 begin和end

typedef typename HashTable<K, K, SetKeyOfT, Hash>::const_iterator iterator;
typedef typename HashTable<K, K, SetKeyOfT, Hash>::const_iterator const_iterator;iterator begin()
{return _ht.begin();
}const_iterator begin() const
{return _ht.begin();
}iterator end()
{return _ht.end();
}const_iterator end() const
{return _ht.end();
}

3 find

iterator find(const K& key)
{return _ht.Find(key);
}

4 insert

pair<iterator, bool> insert(const K& key)
{return _ht.Insert(key);
}

5 erase

bool erase(const K& key)
{return _ht.Erase(key);
}

6.unordered_map

1 成员变量与仿函数

template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{struct MapKeyOfT{const K& operator()(const pair<const K, V>& kv){return kv.first;}};
public:
protected:HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
};
  1. unordered_map类仿函数,返回参数pair的first
  2. 成员变量的第二个模板参数为pair,第三个模板参数为MapKeyOfT
  3. 模板Hash可以根据特定需要而传手动实现的哈希化函数

2 begin和end

typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;
typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::const_iterator const_iterator;iterator begin()
{return _ht.begin();
}const_iterator begin() const
{return _ht.begin();
}iterator end()
{return _ht.end();
}const_iterator end() const
{return _ht.end();
}

3 find

iterator find(const K& key)
{return _ht.Find(key);
}

4 insert

pair<iterator, bool> insert(const pair<const K, V>& kv)
{return _ht.Insert(kv);
}

5 erase

bool erase(const K& key)
{return _ht.Erase(key);
}

6 operator[ ]

V& operator[](const K& key)
{pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;
}

http://www.dtcms.com/wzjs/597920.html

相关文章:

  • 开网站卖茶要怎么做设计师个人网站建设
  • 网络安全网站品牌网站设计步骤
  • 网站服务器重做系统怎么做辽宁住房建设厅网站首页
  • 新余 网站建设公司wordpress 为静态页面
  • 长沙网站托管seo优化公司app拉新怎么做
  • 手机网站 设计图时间轴网站模板
  • 仿站WordPress现在推广一般都用什么软件
  • 专做短篇的网站网站建设与管理心得体会和总结
  • 物流企业网站模板招聘网哪个平台比较好招人
  • 邯郸做wap网站价格网站建设总流程图
  • 设计师导航网站源码android开发技术
  • 一个商城优化seo设置
  • 网页传奇排名聊城网站建设优化
  • 手机网站设计公司哪家好最佳线上网站建设费用
  • 做网站开发很赚钱吗查域名信息
  • 网站两侧对联广告图片公司建设网站服务器必要条件
  • 怎么通过域名做网站软件科技开发公司
  • 国外设计网站h开头建行网站会员是什么
  • 招聘网站大全wordpress文件介绍
  • 大型企业网站建设广州app定制开发
  • 秦皇岛建设工程信息网站wordpress好看的主题
  • 做任务的网站源码许昌市建设路小学网站
  • 网站颜色 字体做网站要用什么服务器
  • 网站推广邮箱怎么做中小企业认定证明
  • 化妆品应如何网站建设定位网址查询ip地址
  • 小说主角重生之后做网站网站是什么公司做的
  • 游戏发号网站源码衡水移动网站建设报价
  • 网站优化建设深圳做网站建设的公司有哪些
  • 《网站设计与建设》电子书网站推广策划书包括哪些点
  • 门户网站的优缺点网站建设流程体会