红黑树的插入、查找、删除的平均时间复杂度为O(nlogn)。当基于假设:输入数据具有随机性时,hashtable插入、查找、删除时间复杂度O(l)。
STL里的hash函数是采用开链法解决碰撞问题,bucket 聚合体是一个vector,便于动态维护,vector里每个元素指向一个bucket list。
如下:
template <class Value> struct __hashtable_node { __hashtable_node* next; Value val; };
hashtable的迭代器是单向的,所以没有后退操作,迭代器实现重要部分如下:
struct __hashtable_iterator { typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> hashtable; typedef __hashtable_node<Value> node; typedef forward_iterator_tag iterator_category; node* cur; // 当前的位置, 是线性表中的链表结点 hashtable* ht; // 线性表中的位置 template <class V, class K, class HF, class ExK, class EqK, class A> __hashtable_iterator<V, K, HF, ExK, EqK, A>& __hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++() { const node* old = cur; cur = cur->next; // 当前链表结点的下一个结点, 如果不为0 // 那么它就是我们要的 // 链表结点恰好是最后一个结点, 我们要在线性表的下一个表格的链表中查找 if (!cur) { size_type bucket = ht->bkt_num(old->val); while (!cur && ++bucket < ht->buckets.size()) cur = ht->buckets[bucket]; } return *this; } template <class V, class K, class HF, class ExK, class EqK, class A> inline __hashtable_iterator<V, K, HF, ExK, EqK, A> __hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++(int) { iterator tmp = *this; ++*this; // 触发operator ++() return tmp; } }
STL中设计表格大小为质数,一般选择“最接近某数并大于某数”
static const int __stl_num_primes = 28; static const unsigned long __stl_prime_list[__stl_num_primes] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 3221225473ul, 4294967291ul }; // 返回大于n的最小素数 inline unsigned long __stl_next_prime(unsigned long n) { const unsigned long* first = __stl_prime_list; const unsigned long* last = __stl_prime_list + __stl_num_primes; const unsigned long* pos = lower_bound(first, last, n); //泛型算法 return pos == last ? *(last - 1) : *pos; }