c++进阶——unordered的封装

在这里插入图片描述

嗨喽大家好呀,今天阿鑫给大家带来的是c++进阶——unordered的封装,好久不见啦,下面让我们进入本节博客的内容吧!

c++进阶——unordered的封装

  1. unordered系列的基本架构
  2. unordered系列迭代器的封装
  3. unordered不支持修改key
  4. operator[]的实现
  5. 两个测试用例

在这里插入图片描述

1. unordered系列的基本架构

#pragma once
#include"HashTable.h"
namespace zj
{
    template<class K,class V>
    class unordered_map
    {
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
    public:
        bool insert(const pair<K, V>& kv)
        {
            return _ht.Insert(kv);
        }


    privete:
        hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;

    };


}
#pragma once
#include"HashTable.h"
namespace zj
{
    template<class K>
    class unordered_set
    {
        struct SetKeyOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };
    public:
        bool insert(const K& key)
        {
            return _ht.Insert(key);
        }
    privete:
        hash_bucket::HashTable<K, K, SetKeyOfT> _ht;

    };


}

KeyOfT用来获取不同data的key

2. unordered系列迭代器的封装

由于哈希表结构的特点,我们对迭代器的封装不能只局限于封装指向节点对象的指针,如果想遍历整个哈希表,我们需要同时将指向哈希表对象的指针进行封装
在这里插入图片描述

template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>
	struct HTIterator
	{
		typedef HashNode<T> Node;
		typedef HTIterator<K, T, Ptr, Ref, KeyOfT, Hash> Self;

		Node* _node;
		const HashTable<K, T, KeyOfT, Hash>* _pht;

		HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht)
			:_node(node)
			,_pht(pht)
		{}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		bool operator!=(const Self& s)
		{
			return _node != s._node;
		}

		Self& operator++()
		{
			if (_node->_next)
			{
				// 当前桶还有节点
				_node = _node->_next;
			}
			else
			{
				// 当前桶走完了,找下一个不为空的桶
				KeyOfT kot;
				Hash hs;
				size_t hashi = hs(kot(_node->_data)) % _pht->_tables.size();
				++hashi;
				while (hashi < _pht->_tables.size())
				{
					if (_pht->_tables[hashi])
					{
						break;
					}

					++hashi;
				}

				if (hashi == _pht->_tables.size())
				{
					_node = nullptr; // end()
				}
				else
				{
					_node = _pht->_tables[hashi];
				}
			}

			return *this;
		}
	};

为了避免编译器向上找不到HashTable,需要加上HashTable的前置声明表面这是个类。

// 前置声明
template<class K, class T, class KeyOfT, class Hash>
class HashTable;

HTIterator需要调用HashTable的私有成员变量_tables,类模板的友元声明需要加上模板

// 友元声明
template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>
friend struct HTIterator;

在Const_Iterator中的成员函数,由于this用const修饰,所以在构造迭代器时形参需要用const的哈希表指针

HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht)
	:_node(node)
	, _pht(pht)
{}

ConstIterator Begin() const
{
	if (_n == 0)
		return End();

	for (size_t i = 0; i < _tables.size(); i++)
	{
		Node* cur = _tables[i];
		if (cur)
		{
			return ConstIterator(cur, this);
		}
	}

	/*return End();*/
}

ConstIterator End() const
{
	return ConstIterator(nullptr, this);
}

在这里插入图片描述

3. unordered不支持修改key

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4. operator[]的实现

operator[]的实现,注意make_pair是构造一个pair对象,pair<x,y>是一个结构体类型

  V& operator[](const K& key)
  {
      //make_pair是用来构造一个pair的
      pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
      return ret.first->second;
  }

5. 两个测试用例

在这里插入图片描述
测试用例1

void test_set1()
{
	unordered_set<int> s = { 3,1,6,7,8,2 };
	/*unordered_set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;*/

	srand(time(0));
	for (size_t i = 0; i < 22000; ++i)
	{
		s.insert(rand()); // N比较大时,重复值比较多
		//v.push_back(rand()+i); // 重复值相对少
		//v.push_back(i); // 没有重复,有序
	}

	/*for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;*/

	cout << s.bucket_count() << endl;
	//cout << s.max_bucket_count() << endl;
	cout << s.size() << endl;
	cout <<"负载因子:" << s.load_factor() << endl;
	cout <<"最大负载因子:" << s.max_load_factor() << endl;

	size_t len = 0;
	size_t nonEmptyBucketSize = 0;
	size_t maxLen = 0;
	for (size_t i = 0; i < s.bucket_count(); i++)
	{
		if (s.bucket_size(i) > 0)
		{
			if (s.bucket_size(i) > maxLen)
				maxLen = s.bucket_size(i);

			len += s.bucket_size(i);
			++nonEmptyBucketSize;
		}
	}
	cout << "平均每个桶的长度:" << (double)len / nonEmptyBucketSize << endl;
	cout << "最大的桶的长度:" << maxLen << endl;
}

测试用例2 ——红黑树和哈希表的对比

int test_set2()
{
	const size_t N = 1000000;

	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()); // N比较大时,重复值比较多
		v.push_back(rand()+i); // 重复值相对少
		//v.push_back(i); // 没有重复,有序
	}

	// 21:15
	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();
	us.reserve(N);
	for (auto e : v)
	{
		us.insert(e);
	}
	size_t end2 = clock();
	cout << "unordered_set insert:" << end2 - begin2 << endl;

	int m1 = 0;
	size_t begin3 = clock();
	for (auto e : v)
	{
		auto ret = s.find(e);
		if (ret != s.end())
		{
			++m1;
		}
	}
	size_t end3 = clock();
	cout << "set find:" << end3 - begin3 << "->" << m1 << endl;

	int m2 = 0;
	size_t begin4 = clock();
	for (auto e : v)
	{
		auto ret = us.find(e);
		if (ret != us.end())
		{
			++m2;
		}
	}
	size_t end4 = clock();
	cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << 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;

	return 0;
}

好啦,今天我们的学习就到这里哦,本节课内容还是有点难度的,希望大家能够好好吸收理解,期待我们的下一次再见

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/873460.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

macos系统内置php文件列表 系统自带php卸载方法

在macos系统中, 自带已经安装了php, 根据不同的macos版本php的版本号可能不同, 我们可以通过 which php 命令来查看mac自带的默认php安装路径, 不过注意这个只是php的执行文件路径. 系统自带php文件列表 一下就是macos默认安装的php文件列表. macos 10.15内置PHP文件列表配置…

软件工程-图书管理系统的概要设计

软件概要设计说明书 目录 软件概要设计说明书 一、引言 1.1 编写目的 1.2 背景 1.3 定义 1.3.1特定对象 1.3.2专业术语 1.4 参考资料 二、总体设计 2.1 需求规定 2.1.1信息要求 2.1.2功能要求 2.2 运行环境 2.3 基本概要设计和处理流程 2.4 体系结构设计 2.5 模…

基于微信小程序在线订餐系统

微信小程序在线订餐系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了微信小程序在线订餐系统的开发全过程。通过分析微信小程序在线订餐系统管理的不足&#xff0c;创建了一个计算机管理微信小程序在线订…

【Python基础】Python函数

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、函数的定义与调用三、函数参数3.1 位置参数3.2 默认参数3.3 可变数量参数&#xff08;或不定长参数…

Kubernetes 简介及部署方法

目录 一、Kubernetes简介 1 应用部署方式演变 1.2 容器编排应用 1.3 kubernetes 简介 1.4 K8S的设计架构 1.4.1 K8S各个组件用途 1.4.2 K8S 各组件之间的调用关系 1.4.3 K8S 的 常用名词感念 1.4.4 k8S的分层架构 二 K8S集群环境搭建 2.1 k8s中容器的管理方式 2.2 …

网络安全知识:什么是访问控制列表 (ACL)?

访问控制列表 (ACL) 是网络安全和管理的基础。它们在确定谁或什么可以访问网络内的特定资源方面发挥着重要作用。 本文深入探讨了 ACL 的复杂性&#xff0c;探索了其类型、组件、应用程序和最佳实践。我们还将比较不同操作系统的 ACL&#xff0c;并讨论它们在网络架构中的战略…

生信圆桌x生信分析平台:助力生物信息学研究的综合工具

介绍 少走弯路,高效分析;了解生信云,访问 【生信圆桌x生信专用云服务器】 : www.tebteb.cc 生物信息学的迅速发展催生了众多生信分析平台&#xff0c;这些平台通过集成各种生物信息学工具和算法&#xff0c;极大地简化了数据处理和分析流程&#xff0c;使研究人员能够更高效地…

如何使div居中?CSS居中终极指南

前言 长期以来&#xff0c;如何在父元素中居中对齐一个元素&#xff0c;一直是一个让人头疼的问题&#xff0c;随着 CSS 的发展&#xff0c;越来越多的工具可以用来解决这个难题&#xff0c;五花八门的招式一大堆&#xff0c;这篇博客&#xff0c;旨在帮助你理解不同的居中方法…

EVO进行轨迹评估

EVO进行轨迹评估 文章目录 EVO进行轨迹评估1 前言1.1 轨迹对齐1.2 尺度变换1.3 绝对轨迹误差ATE和相对轨迹误差RTE1.4 绝对姿态误差APE和相对姿态误差RPE 2 安装evo2.1 evo安装2.2 相关报错2.2.1 版本不兼容问题2.2.2 解决PATH警告 2.3 测试 3 evo指令3.1 evo_traj3.2 evo_ape3…

Spring Boot3.x 启动自动执行sql脚本

1 引言 某些项目在首次启动时&#xff0c;需要先手动创建数据库表&#xff0c;然后再手动写入初始数据才能正常使用。为了省去这个手动操作过程&#xff0c;我们可以使用Spring Boot启动时执行sql脚本的配置&#xff0c;全自动完成这个过程。 2 配置 具体配置如下&#xff1…

Python 调用手机摄像头

Python 调用手机摄像头 在手机上安装软件 这里以安卓手机作为演示&#xff0c;ISO也是差不多的 软件下载地址 注意&#xff1a;要想在电脑上查看手机摄像头拍摄的内容的在一个局域网里面(没有 WIFI 可以使用 热点 ) 安装完打开IP摄像头服务器 点击分享查看IP 查看局域网的I…

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况&#xff1a; 代…

flume 使用 exec 采集容器日志,转储磁盘

flume 使用 exec 采集容器日志&#xff0c;转储磁盘 在该场景下&#xff0c;docker 服务为superset&#xff0c;flume 的sources 选择 exec &#xff0c; sinks选择 file roll 。 任务配置 具体配置文件如下&#xff1a; #simple.conf: A single-node Flume configuration#…

Shader 渲染路径

实际的游戏开发中&#xff0c;场景中的光源肯定是更多、更复杂的&#xff0c;如果只有一个平行光的处理&#xff0c;完全不能满足需求。处理更多的光源&#xff0c;我们就需要了解Unity底层是如何处理这些光源的。 1、渲染路径是什么 渲染路径&#xff08;Rendering Path&…

Apache POl的使用(导出报表)

介绍 Apache POl是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用 PO! 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。一般情况下&#xff0c;POI都是用于操作 Excel 文件。 Apache POl的应用场景: 银行网银系统导出交…

中秋之美——html5+css+js制作中秋网页

中秋之美——html5cssjs制作中秋网页 一、前言二、功能展示三、系统实现四、其它五、源码下载 一、前言 八月十五&#xff0c;秋已过半&#xff0c;是为中秋。 “但愿人长久&#xff0c;千里共婵娟”&#xff0c;中秋时节&#xff0c;气温已凉未寒&#xff0c;天高气爽&#x…

助贷行业的三大严峻挑战:贷款中介公司转型债务重组业务

大家是否察觉到一种趋势&#xff1f;现如今&#xff0c;众多贷款辅助服务机构与专注于债务再构的公司之间形成了紧密的“联动”。有的选择将获取的贷款需求转介给债务重组方&#xff0c;有的则直接下场&#xff0c;动用自身资本参与债务重组业务。这一现象背后&#xff0c;究竟…

紫光展锐完成Android 15同步升级,驱动技术创新与生态共赢

近日&#xff0c;紫光展锐宣布&#xff0c;展锐5G移动平台T820、T770、T765、T760、T750以及4G平台T620、T619、T616、T615、T612、T606&#xff0c;完成Android 15同步升级。相较于过往Android发布&#xff0c;今年同步升级Android 15主要有三大提升&#xff1a; ■ 紫光展锐实…

Oracle版本简介手册

Oracle版本简介手册 图1—数据库发布路线图表 Oracle数据库的各个版本反映了其技术的发展历程和功能增强&#xff0c;从最早的Oracle 1&#xff08;1979年&#xff09;到最新的版本&#xff0c;每个版本都带来了新的特性和改进&#xff0c;以满足不断变化的企业需求。以下是Or…

2024 第七届“巅峰极客”网络安全技能挑战赛初赛 Web方向 题解WirteUp

EncirclingGame 题目描述&#xff1a;A simple game, enjoy it and get the flag when you complete it. 开题&#xff0c;前端小游戏&#xff0c;红点出不去就行 直接玩通关了 看看如何不玩也能拿到flag&#xff0c;flag存储在后端php文件内&#xff0c;前端找不到。 看一下…