STL与泛型编程 week 3 (Boolan)

deque&queue和stack深度探索

deque的定义(C++ Primer):

Sequential container. Elements in a deque can be accessed by their positional index. Supports fast random access to elements. Like a vector in all respects except that it supports fast insertion and deletion at the front of the container as well as at the back and does not relocate elements as a result of insertions or deletions at either end.

  • deque是双向开口容器,它模拟了一个连续的存储空间(实质为连续分段的容器),其中buffer和元素结点设计如下图所示:


    stl3_1.png

    其中buffer为deque的缓冲区, 每个buffer可以存放多个元素结点, 而每个buffer指针存放在vector容器中.

  • G2.9版的deque:


    stl3_02.png
  • deque的iterator (deque如何模拟连续空间, 全都是deque iterator的功劳):


    stl3-03.png

    每个iterator有四个指针: cur(当前数据结点的指针)、first(buffer首指针)、last(buffer的尾指针)、node(node表示这个iterator在vector中的指针地址).

G2.9版queue:


stl3-04.png

G2.9版stack:


stl3-05.png

容器rb_tree

Red-Black tree (红黑树) 是平衡二元搜寻树 (balanced binary search tree) 中常被使用的一种. 平衡二元搜寻树的特征: 排列规则有利于search 和 insert, 并保持适度平衡----无任何节点过深.

rb_tree提供"遍历"操作及iterators. 按正常规则(++ite)遍历, 便能获得排序状态.

我们不应使用rb_tree的iteraotr改变元素值(因为元素有其严谨的排列规则). 编程层面(programming level)并未阻绝此事. 如此设计是正确的, 因为rb_tree即将为set 和 map 服务(做为其底部支持), 而map允许元素的data 被改变, 只有元素的key才是不可被改变的.

rb_tree 提供两种insertion操作: insert_unique()insert_equal(). 前者表示节点的key一定在整个tree中独一无二, 否则安插失败;后者表示节点的key可重复.

G2.9版rb_tree:

template <class Key,
          class Value,
          class KeyOfValue,
          class Compare,
          class Alloc = alloc>
class rb_tree {
 protected:
  typedef  __rb_tree_node<Value> rb_tree_node;
  ...
 public:
  typedef rb_tree_node* link_type;
  ...
 protected:
  // RB-tree 只有三笔资料表现自己
  size_type node_count;  // rb_tree的大小(节点数量)
  link_type header;
  Compare key_compare;  // Key的大小比较准则: 应会是个function object
};
  • 定义一个简单rb_tree class的对象:
template <class Arg, class Result>
struct unary_function {
  typedef Arg argument_type;
  typedef Result result_type;
};

template <class Arg1, class Arg2, class Result>
struct binary_function {
  typedef Arg1 first_argument_type;
  typedef Arg2 first_argument_type;
  typedef Result result_type;
};

template <class T>
struct identity : public unary_function<T, T> {
  const T& operator()(const T &x) const { return x; }
};

template <class T>
struct less : public binary_function <T, T, bool> {
  bool operator() (const T &x, const T &y) const 
  { return x < y; }
};
  • 容器rb_tree的用例
rb_tree<int, int, identity<int>, less<int>> itree;
cout << itree.empty() << endl;  // 1
cout << itree.size() << endl;  // 0

itree.insert_unique(3);
itree.insert_unique(8);
itree.insert_unique(5);
itree.insert_unique(9);
itree.insert_unique(13);
itree.insert_unique(5);  // 不会有用, 因为这里是insert_unique()
cout << itree.empty() << endl;  // 0
cout << itree.size() << endl;  // 5
cout << itree.count(5) << endl;  // 1

itree.insert_equal(5);
itree.insert_equal(5);
cout << itree.size() << endl;  // 7, since using insert_equal().
cout << itree.count(5) << endl;  // 3

红黑树的特性 (摘自Introduction to algorithms)

A red-black tree is a binary search tree with one extra bit of storage per node: its color, which can be either RED or BLACK . By constraining the node colors on any simple path from the root to a leaf, red-black trees ensure that no such path is more than twice as long as any other, so that the tree is approximately balanced.
Each node of the tree now contains the attributes color, key, left, right, and p. If a child or the parent of a node does not exist, the corresponding pointer attribute of the node contains the value NIL . We shall regard these NIL s as being pointers to leaves (external nodes) of the binary search tree and the normal, key-bearing nodes as being internal nodes of the tree.
A red-black tree is a binary tree that satisfies the following red-black properties:

  • Every node is either red or black.
  • The root is black.
  • Every leaf ( NIL ) is black.
  • If a node is red, then both its children are black.
  • For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.

容器set, multiset

set/multiset以rb_tree为底层结构, 因此有"元素自动排序"特性. 排序的依据是key, 而set/multiset元素的value和key合一: value就是key.

set/multiset提供"遍历"操作及iterators. 按正常规则(++ite)遍历, 便能获得排序状态(sorted).

我们无法使用set/multiset的iterator改变元素值(因为key有其严谨排列规则). set/multiset的iterator是其地步的RB tree的const iterator, 就是为了禁止user对元素赋值.

set元素的key必须独一无二, 因此其insert()用的是rb_tree的insert_unique(). multiset元素的key可以重复, 因此其insert()用的是rb_tree的insert_equal().

  • G2.9版set:
template <class Key,
          class Compare = less<Key>,
          class Alloc = alloc>
class set {
 public:
  // typedefs:
  typedef Key key_type;
  typedef Key value_type;
  typedef Compare key_compare;
  typedef Compare value_compare;
 private:
  typedef rb_tree<key_type, value_type, 
                  identity<value_type>, key_compare, Alloc> rep_type;
  rep_type t;
 public:
  typedef typename rep_type::const_iterator iterator;
...
};

容器map,multimap

map/multimap以rb_tree为底层结构, 因此有“元素自动排序”特性。 排序的依据是key。

map/multimap提供"遍历"操作及iterators。按正常规则(++ite)遍历, 便能获得排序状态(sorted)。

我们无法使用map/multimap的iterators改变元素的key(因为key有其严谨排序规则), 但可以用它来改变元素的data。 因此map/multimap内部自动将user制定的key type设为const, 如此便能禁止user对元素的key赋值。

map元素的key必须独一无二, 因此其insert()用的是rb_tree的insert_unique(). multimap元素的key可以重复, 因此其insert()用的是rb_tree的insert_equal().

G2.9版map:

template <class Key,
          class T,
          class Compare = less<Key>,
          class Alloc = alloc>
class map {
 public:
  typedef Key key_type;
  typedef T data_type;
  typedef T mapped_type;
  typedef pair<const Key, T> value_type;
  typedef Compare key_compare;
 private:
  typedef rb_tree<key_type, value_type, 
                  select1st<value_type>, key_compare, Alloc> rep_type;
  rep_type t;
 public:
  typedef typename rep_type::iterator iterator;
...
};

容器hashtable

  • G2.9版hashtable:
template <class Value>
struct __hashtable_node {
  __hashtable_node *next;
  Value val;
};

template <class Value, class Key, class HashFun,
          class ExtractKey, class EqualKey
          class Alloc = alloc>
class hashtable {
 public:
  typedef HashFcn hasher;
  typedef EqualKey key_equal;
  typedef size_t size_type;

 private:
  hasher hash;
  key_equal equals;
  ExtractKey get_key;

  typedef __hashtable_node<Vlaue> node;

  vector<node*, Alloc> buckets;
  size_type num_elements;
 public:
  size_type bucket_count() const { return buckets.size(); }
};

template <class Value, class Key,
          class HashFcn, class ExtractKey,
          class EqualKey, class Alloc>
struct __hashtable_iterator {
...
  mode *cur;
  hashtable *ht;
};
  • hashtable用例:
struct eqstr {
  bool operator()(const char *s1, const char *s2) const
  { return strcmp(s1, s2) == 0; }
};

hashtable <const char*,
           const char*,
           hash<const char*>,
           identity<const char*>,
           eqstr,
           alloc>
ht(50, hash<const char*>(), eqstr());

ht.insert_unique("kiwi");
ht.insert_unique("plum");
ht.insert_unique("apple");

hash-function, hash-code

// 泛化
template <class Key> struct hash { };

// 特化
template <> struct hash <char> {
  size_t operator() (char x) const { return x; }
};

template <> struct hash <short> {
  size_t operator() (short x) const { return x; }
};

template <> struct hash <unsigned short> {
  size_t operator() (unsigned short x) const { return x; }
};

template <> struct hash <int> {
  size_t operator() (int x) const { return x; }
};

template <> struct hash <unsigned int> {
  size_t operator() (unsigned int x) const { return x; }
};

template <> struct hash <long> {
  size_t operator() (long x) const { return x; }
};

template <> struct hash <unsigned long> {
  size_t operator() (unsigned long x) const { return x; }
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容