C++:关联性容器及底层实现

(缺少代码实战之后补)

1关联性容器:

类似一个小型数据库
所用数据结构:
红黑树以及哈希表(散列表)

2红黑树(rb_tree)

2.1定义及性质(具体实现看数据结构红黑树)

  • 是一个平衡二叉树搜索树。优势是排列规则有利查找插入,时间复杂度log(N),排列适度没有任一节点过深。
  • 红黑树提供迭代器以及遍历操作。形成中序遍历进行查找搜索。
++iter; //获得排序状态,中序遍历的情况(左中右)

结果:g->d->h->b->a->e->c->f
在这里插入图片描述

  • 不应该使用红黑树iter改变元素值(红黑树是二叉搜索树)。变成没有拒绝因为他为map和set服务,此时map的data可以改,但是用来排序的key不可以修改。
  • rb_tree插入操作:
insert_unique();//key在整个数中独一无二,否则安插失败
insert_equal();//节点key可重复

2.2c++实现

  • 红黑树是一个类模板,类目参数类型列表包括:key类型,key-data键值对类型,值类型、比较函数、alloc
  • 红黑树成员包括:
    size_type node_count; 红黑树容量
    link_type header; //节点指针
    Compare key_compare;//仿函数

3 set、multiset

  • set和multiset以rb_tree为底层结构,有元素自动排序的特性,排序依据是key,因为set、multiset元素只有key。
  • set/multiset提供遍历操作以及迭代器,按++iter遍历,就是排序状态。
  • 无法使用iterator改变元素值,set/multiset底部是const iterator,禁止修改。
  • set用的插入是insert_unique(),multiset使用的是insert_equal。
  • set将红黑树做为基类,初始化时是对基类进行初始化(也类似适配器)
class set : public _Tree<_Tset_traits<_Kty, _Pr, _Alloc, false>> 
using _Mybase                = _Tree<_Tset_traits<_Kty, _Pr, _Alloc, false>>;
static const _Kty& _Kfn(const value_type& _Val) { //返回key类型是const类型 
        return _Val;
    }
set() : _Mybase(key_compare()) {}


4map、multimap

  • value里时key-data。key不可改,data可以改。
  • 可以将key_type设为const
  • map用的插入是insert_unique(),multimap使用的是insert_equal。
  • 初始化与set类似。
template <class _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty>>>
class map : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>> {
using _Mybase                = _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>>;
using value_type             = pair<const _Kty, _Ty>;  //将key设为const,data可以修改

  • map的operator[]:下标查找实际是使用二分法实现lower_bound()查找,key不存在创建key到map里(没data存默认值)

5容器hashtable、散列表

5.1原理

  • 假设对于某一种情况,有M种可能方式,设其中一种情况为T,则对于一个包含所有情况的列表,对应序号0~M-1,需要M*sizeof(T)的内存。
  • 当容量足够时:一个萝卜一个坑,把值放在对应位置索引就行。
012M-1
  • 当容量不足时:需要进行缩减,假设需要将内存缩减至N大小,N<M*sizeof(T)。然后将T对象放在T对应序号K%N的位置。
012N-1

5.2 哈希碰撞:

  • 问题:可能存在对于不同序号,需要放在同一个索引的情况,叫做哈希碰撞。
    解决:起初设计函数把后来的挪到其他位置。后来考虑算法复杂度的提升,故将同一个索引的值通过链表的形式串在一起(Separate Chaining)。
    N =53,M = 200
    在这里插入图片描述
  • 再次问题:从前到后依次串起来,链表可能会很长,搜索很慢
    解决:当链表过长时就打散开来(bucket)。增加二倍篮子,重新计算被链接的元素位置(不在列表中的个数)。
    N:97,M:200
    在这里插入图片描述
  • 经验:
    1.打散经验:如果被链接元素个数(不在列表中的个数)大于篮子个数,就危险,需要打散。此时rehashing,增加两倍篮子。
    2.篮子数经验:一般篮子数会选为质数。

5.3代码实现

  • 类模板参数:Value、Key、Hasher、ExtractKey、Keyeq、Alloc

Hasher:编号方法
ExtractKey:取key方法
Keyeq:key比较方法

  • 迭代器设计
  • hasher:对于自定义的类要做类模板特例化:
namespace std{
template<>
	struct hash<Sales_data>{
		typedef size_t result_type;
		typedef Sales_data argument_type;
		size_t operator()(const Sales_data& s)const{
		return hash<string>()(s.bookNo)^
			hash<unsigned>()(s.units_sold)^
			hash<double>()(s.revenue);
		}
	};
}

6 unordered 不定序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值