[Happy Coding] 一段调用STL算法的程序代码的效率分析

已知一个STD::SET,想要根据一个predicate来从中去除所有的满足predicate(返回true)的元素。

我们首先想到的是STL提供的remove_if函数。
下面我们来看看这个函数是如何实现的:

1133   template<typename _ForwardIterator, typename _Predicate>
1134     _ForwardIterator
1135     remove_if(_ForwardIterator __first, _ForwardIterator __last,
1136           _Predicate __pred)
1137     {
1144
1145       __first = std::find_if(__first, __last, __pred);
1146       _ForwardIterator __i = __first;
1147       return __first == __last ? __first
1148                    : std::remove_copy_if(++__i, __last,
1149                              __first, __pred);
1150     }

 这个函数首先调用std::find_if来干活,下面来看看std::find_if的实现过程:
std::find_if提供了很多重载版本,主要根据iterator的类型:
由于我们的std::set不是randomIterator,所以就会调用到下面的函数:
182   template<typename _InputIterator, typename _Predicate>
183     inline _InputIterator
184     find_if(_InputIterator __first, _InputIterator __last,
185         _Predicate __pred, input_iterator_tag)
186     {
187       while (__first != __last && !__pred(*__first))
188     ++__first;
189       return __first;
190     }

可以看到,这个函数迭代的查看每一个元素,判断是否满足predicate的要求。

我们来看看std::remove_copy_if函数。
当找到第一个满足条件的元素之后,便从这个元素开始来调用remove_copy_if函数。

1059   template<typename _InputIterator, typename _OutputIterator,
1060        typename _Predicate>
1061     _OutputIterator
1062     remove_copy_if(_InputIterator __first, _InputIterator __last,
1063            _OutputIterator __result, _Predicate __pred)
1064     {
1072
1073       for ( ; __first != __last; ++__first)
1074     if (!__pred(*__first))
1075       {
1076         *__result = *__first;
1077         ++__result;
1078       }
1079       return __result;
1080     }
这个函数也是迭代的查看每一个元素,判断是否满足要求,不满足条件的(!__pred(*__first)),将它COPY到输出容器中。
请注意这个操作,按照 remove_if传递进来的输入输出迭代器,来自于同一个容器,
a) 如果后面没有任何元素满足predicate的条件,那么这个函数将仅仅只是LOOP那些元素而已。
b) 如果后面的元素有一些满足predicate的条件,那么这个赋值操作是否做什么事情,将取决于容器内元素提供的赋值操作符实现。如果元素的赋值操作符实现进行了自赋值检查(什么都不做),那么这个赋值将不会花销任何时间,否则对于自定义的类型可能就会有较大的开销。

所以用std::remove_if来针对std::set进行操作,效率比较低效,原因在于stl提供的算法都无法知晓具体容器的特点,它们只能根据容器提供的迭代接口来遍历容器,进行操作。所以更有效的方法就是调用这些容器自己提供的接口,例如std::set::find

1095   template<typename _Key, typename _Val, typename _KeyOfValue,
1096            typename _Compare, typename _Alloc>
1097     typename _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::iterator
1098     _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::find(const _Key& __k)
1099     {
1100       _Link_type __x = _M_begin(); // Current node.
1101       _Link_type __y = _M_end(); // Last node which is not less than __k.
1102
1103       while (__x != 0)
1104     if (!_M_impl._M_key_compare(_S_key(__x), __k))
1105       __y = __x, __x = _S_left(__x);
1106     else
1107       __x = _S_right(__x);
1108
1109       iterator __j = iterator(__y);
1110       return (__j == end()
1111       || _M_impl._M_key_compare(__k, _S_key(__j._M_node))) ? end() : __j;
1112     }

它基于内部的二叉树结构来快速的查找满足条件的元素。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
王晓东的《算法设计与分析》是一本经典的算法教材,而哈夫曼编码是其中的一种重要算法。哈夫曼编码是一种前缀编码方式,可以将字符集中的每个字符映射成唯一的二进制编码,并且保证编码长度最短,从而实现压缩数据的目的。 下面是哈夫曼编码的C++实现代码,代码注释中有详细的说明: ```c++ #include<iostream> #include<queue> #include<vector> #include<string> #include<fstream> #include<sstream> using namespace std; //节点类 class Node{ public: char ch; int freq; Node* left; Node* right; Node(char c, int f){ ch = c; freq = f; left = nullptr; right = nullptr; } //定义比较函数,用于优先队列中节点的排序 bool operator<(const Node& node) const{ return freq > node.freq; } }; //哈夫曼树类 class HuffmanTree{ public: Node* root; HuffmanTree(){ root = nullptr; } //创建哈夫曼树 void createHuffmanTree(vector<Node*>& nodes){ priority_queue<Node> pq; for(int i=0; i<nodes.size(); i++){ pq.push(*nodes[i]); } while(pq.size() > 1){ Node* left = new Node(pq.top().ch, pq.top().freq); pq.pop(); Node* right = new Node(pq.top().ch, pq.top().freq); pq.pop(); Node* parent = new Node('#', left->freq+right->freq); parent->left = left; parent->right = right; pq.push(*parent); } root = new Node(pq.top().ch, pq.top().freq); } //生成哈夫曼编码 void generateHuffmanCode(Node* node, string code, vector<pair<char,string>>& codeTable){ if(!node->left && !node->right){ codeTable.push_back(make_pair(node->ch, code)); return; } generateHuffmanCode(node->left, code+"0", codeTable); generateHuffmanCode(node->right, code+"1", codeTable); } }; //读取文件内容,并统计每个字符出现的次数 void readData(string fileName, vector<Node*>& nodes){ ifstream file(fileName); if(file.is_open()){ stringstream buffer; buffer << file.rdbuf(); string contents(buffer.str()); int count[256] = {0}; for(int i=0; i<contents.size(); i++){ count[contents[i]]++; } for(int i=0; i<256; i++){ if(count[i] > 0){ char ch = (char)i; int freq = count[i]; Node* node = new Node(ch, freq); nodes.push_back(node); } } file.close(); } } int main(){ string fileName = "test.txt"; vector<Node*> nodes; readData(fileName, nodes); HuffmanTree huffmanTree; huffmanTree.createHuffmanTree(nodes); vector<pair<char,string>> codeTable; huffmanTree.generateHuffmanCode(huffmanTree.root, "", codeTable); cout << "Huffman coding table:" << endl; for(int i=0; i<codeTable.size(); i++){ cout << codeTable[i].first << ": " << codeTable[i].second << endl; } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值