采用C++11实现一款简易的STL标准库,既是C++STL的一个子集(裁剪了一些容器和算法)又是一个超集(增加了一些容器和算法)
目的:练习数据结构与算法和C++ Template编程
编译环境:VS2013及以上版本
##开发计划:
- STL的几大基本组件,如string、vector、list、deque、set、map、unordered_*等
- STL算法库中的大部分算法
- circular buffer
- bitmap
- skip list
- binary search tree
- AVL tree
- rbtree
- segment tree
- splay tree
- rope
- Van Emde Boas tree
- treap
- B-tree
- trie
- suffix array/tree
- Disjoint-set data structure
- k-d tree
- R-tree
- Matrix
- Graph
- bloom filter
##完成进度:
- STL的几大基本组件
- type traits:100%
- 空间配置器:100%
- iterator traits:100%
- reverse_iterator:100%
- vector:100%
- string:100%
- priority_queue:100%
- stack:100%
- deque:100%
- queue:100%
- pair:100%
- list:100%
- unordered_set:100%
- unique_ptr:100%
- shared_ptr:100%
- cow_ptr:100%
- STL Algorithms:
- fill:100%
- fill_n:100%
- find:100%
- is_heap:100%
- min、max:100%
- make_heap:100%
- pop_heap:100%
- push_heap:100%
- sort_heap:100%
- swap:100%
- all_of:100%
- any_of:100%
- none_of:100%
- find_if:100%
- find_if_not:100%
- adjacent_find:100%
- count:100%
- count_if:100%
- mismatch:100%
- equal:100%
- is_permutation:100%
- search:100%
- advance:100%
- sort:100%
- generate:100%
- generate_n:100%
- distance:100%
- copy:100%
- 其他组件:
- circular_buffer:100%
- bitmap:100%
- binary_search_tree:100%
- avl_tree:100%
- suffix_array:100%
- directed_graph:100%
- trie tree:100%
- Disjoint-set data structure:100%
##TinySTL单元测试(原单元测试代码逐步):
- pair:100%
- algorithm:20%
- vector:100%
- string:100%
- priority_queue:100%
- suffix_array:100%
- queue:100%
- stack:100%
- bitmap:100%
- circular_buffer:100%
- deque:100%
- list:100%
- binary_search_tree:100%
- avl_tree:100%
- unordered_set:100%
- directed_graph:100%
- trie tree:100%
- unique_ptr:100%
- shared_ptr:100%
- Disjoint-set data structure:100%
#TinySTL性能测试: ###测试环境:Windows 7 && VS2013 && release模式 ###测试结果: ####(1):vector<int>
//std::vector<int> vec; TinySTL::vector<int> vec; ProfilerInstance::start(); int i = 0; for (; i != 10000; ++i){ vec.push_back(i); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::vector<int> | 10万 | 2 |
| TinySTL::vector<int> | 100万 | 11 |
| TinySTL::vector<int> | 1000万 | 129 |
| std::vector<int> | 10万 | 6 |
| std::vector<int> | 100万 | 16 |
| std::vector<int> | 1000万 | 210 |
| ####(2):vector<string> |
//std::vector<std::string> vec; TinySTL::vector<std::string> vec; ProfilerInstance::start(); int i = 0; for (; i != 100000; ++i){ vec.push_back(std::string("zouxiaohang")); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::vector<string> | 10万 | 18 |
| TinySTL::vector<string> | 100万 | 181 |
| TinySTL::vector<string> | 1000万 | 2372 |
| std::vector<string> | 10万 | 29 |
| std::vector<string> | 100万 | 232 |
| std::vector<string> | 1000万 | 1972 |
| ####(3):circular_buffer<int, N> |
TinySTL::circular_buffer<int, 10000> cb(10000, 0); //boost::circular_buffer<int> cb(10000, 0); ProfilerInstance::start(); for (int i = 0; i != 10000000; ++i){ cb.push_back(i); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::circular_buffer | 1000万 | 75 |
| TinySTL::circular_buffer | 10000万 | 604 |
| TinySTL::circular_buffer | 100000万 | 5936 |
| boost::circular_buffer | 1000万 | 22 |
| boost::circular_buffer | 10000万 | 252 |
| boost::circular_buffer | 100000万 | 2241 |
| ####(4):题目:利用bitmap找出str中未出现的字母 |
std::string str("abcdefghijklmnpqrstuvwxyz"); TinySTL::bitmap<26> bm; for (auto it = str.cbegin(); it != str.cend(); ++it){ bm.set(*it - 'a'); } cout << bm << endl; cout << bm.size() << endl; for (int i = 0; i != 26; ++i){ if (!bm.test(i)) cout << "字母" << (char)('a' + i) << "没出现!!!" << endl; } 输出结果:
111111111111110111111111111000000 32 字母o没出现!!! ####(5):string
//std::string str; TinySTL::string str; ProfilerInstance::start(); int i = 0; for (; i != 1000000; ++i){ str.push_back('x'); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::string | 100万 | 7 |
| TinySTL::string | 1000万 | 39 |
| TinySTL::string | 10000万 | 484 |
| std::string | 100万 | 37 |
| std::string | 1000万 | 229 |
| std::string | 10000万 | 1965 |
####(6):priority_queue<int>
//std::priority_queue<int> pq; TinySTL::priority_queue<int> pq; ProfilerInstance::start(); int i = 0; for (; i != 100000; ++i){ pq.push(i); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::priority_queue<int> | 10万 | 13 |
| TinySTL::priority_queue<int> | 100万 | 97 |
| TinySTL::priority_queue<int> | 1000万 | 1032 |
| std::priority_queue<int> | 10万 | 12 |
| std::priority_queue<int> | 100万 | 67 |
| std::priority_queue<int> | 1000万 | 752 |
TinySTL::vector<int> v; int i = 0; for (; i != 100000; ++i){ v.push_back(i); } //std::priority_queue<int> pq(v.begin(), v.end()); TinySTL::priority_queue<int> pq(v.begin(), v.end()); ProfilerInstance::start(); for (i = 0; i != 100000; ++i){ pq.pop(); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::priority_queue<int> | 10万 | 19 |
| TinySTL::priority_queue<int> | 100万 | 137 |
| TinySTL::priority_queue<int> | 1000万 | 1532 |
| std::priority_queue<int> | 10万 | 7 |
| std::priority_queue<int> | 100万 | 92 |
| std::priority_queue<int> | 1000万 | 1214 |
####(7):binary_search_tree<string>
ifstream f; //char buff[256] = { 0 }; std::string word; f.open("C:\\Users\\zxh\\Desktop\\text.txt"); TinySTL::vector<TinySTL::string> v; while (f.good()){ f >> word; //std::copy(word.begin(), word.end(), buff); //v.push_back(TinySTL::string(buff, buff + word.size())); v.push_back(word); } TinySTL::binary_search_tree<TinySTL::string> sbst; ProfilerInstance::start(); for (const auto& word : v){ sbst.insert(word); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); f.close(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::binary_search_tree<string> | 44067 | 16 |
| TinySTL::binary_search_tree<string> | 169664 | 64 |
| TinySTL::binary_search_tree<string> | 438230 | 277 |
####(8):deque<int>
//std::deque<int> dq; TinySTL::deque<int> dq; ProfilerInstance::start(); const int max = 10000000; int i = 0; for (; i != max / 2; ++i){ dq.push_front(i); } for (; i != max; ++i){ dq.push_back(i); } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::deque<int> | 10万 | 15 |
| TinySTL::deque<int> | 100万 | 78 |
| TinySTL::deque<int> | 1000万 | 1186 |
| std::deque<int> | 10万 | 90 |
| std::deque<int> | 100万 | 1087 |
| std::deque<int> | 1000万 | 4835 |
| #####ps:这个性能差距的原因1是内部实现的机制不同,我的deque是预先分配内存因此相同条件下占用的内存更多,而stl的deque是需要的时候再分配,更加节省内存;2是stl的deque实现了更多更灵活的插入删除操作,我只是实现了在头尾的插入和删除 |
####(9):avl_tree<int> TinySTL::binary_search_tree bst; TinySTL::avl_tree avlt; for (int i = 0; i != 10000; ++i){ avlt.insert(i); bst.insert(i); } cout << "binary_search_tree height = " << bst.height() << endl; cout << "avl_tree height = " << avlt.height() << endl; 输出结果:
binary_search_tree height = 10000 avl_tree height = 14 ####(10):list<int>
TinySTL::list<int> list; //std::list<int> list; const size_t max = 100000; ProfilerInstance::start(); for (size_t i = 0; i != max; ++i) list.push_back(i); ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | time(ms) |
|---|---|---|
| TinySTL::list<int> | 10万 | 4 |
| TinySTL::list<int> | 100万 | 33 |
| TinySTL::list<int> | 1000万 | 286 |
| std::list<int> | 10万 | 189 |
| std::list<int> | 100万 | 1774 |
| std::list<int> | 1000万 | 17571 |
####(11):list<int>::sort()
TinySTL::list<int> list1; std::list<int> list2; std::default_random_engine dre; std::uniform_int_distribution<int> id; const size_t max = 10000; for (int i = 0; i != max; ++i){ auto n = id(dre); list1.push_back(n); list2.push_back(n); } double cost1 = 0.0, cost2 = 0.0; for (int i = 0; i != 100; ++i){ ProfilerInstance::start(); list1.sort();//TinySTL::list<int> ProfilerInstance::finish(); cost1 += ProfilerInstance::millisecond(); ProfilerInstance::start(); list2.sort();//std::list<int> ProfilerInstance::finish(); cost2 += ProfilerInstance::millisecond(); } cout << "TinySTL time: " << cost1 / 100 << "ms" << endl; cout << "std time: " << cost2 / 100 << "ms" << endl; | container | quantity | time(ms) |
|---|---|---|
| TinySTL::list<int> | 1万 | 0.88 |
| TinySTL::list<int> | 10万 | 17.621 |
| TinySTL::list<int> | 100万 | 591.354 |
| std::list<int> | 1万 | 1.25 |
| std::list<int> | 10万 | 35.692 |
| std::list<int> | 100万 | 665.128 |
####(12):suffix_array
char arr[] = { 'a', 'a', 'b', 'a', 'a', 'a', 'a', 'b' }; TinySTL::suffix_array sa(arr, 8); auto suffixArray = sa.suffixArray(); auto rankArray = sa.rankArray(); auto heightArray = sa.heightArray(); TinySTL::Test::print_container(suffixArray, "suffixArray"); TinySTL::Test::print_container(rankArray, "rankArray"); TinySTL::Test::print_container(heightArray, "heightArray"); ####(13):unordered_set<int>
TinySTL::Unordered_set<int> ust(10); //std::unordered_set<int> ust(10); const size_t insert_count = 1000000; const uint64_t query_count = 100000000; //calculate total insert time ProfilerInstance::start(); for (size_t i = 0; i != insert_count; ++i){ ust.insert(i);//per insert time } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); //calculate total query time ProfilerInstance::start(); for (uint64_t i = 0; i != query_count; ++i){ ust.count(i);//per query time } ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | container | quantity | insert time(ms) | query time(ms) |
|---|---|---|---|
| TinySTL::unordered_set<int> | 1万/1亿 | 8 | 97 |
| TinySTL::unordered_set<int> | 10万/10亿 | 139 | 1000 |
| TinySTL::unordered_set<int> | 100万/100亿 | 1214 | 9546 |
| std::unordered_set<int> | 1万/1亿 | 64 | 101 |
| std::unordered_set<int> | 10万/10亿 | 884 | 953 |
| std::unordered_set<int> | 100万/100亿 | 2781 | 9682 |
####(14):sort
std::random_device rd; const int len = 10000000; int arr[len]; std::generate(std::begin(arr), std::end(arr), [&rd](){return rd(); }); ProfilerInstance::start(); TinySTL::sort(std::begin(arr), std::end(arr)); //std::sort(std::begin(arr), std::end(arr)); ProfilerInstance::finish(); ProfilerInstance::dumpDuringTime(); | algorithm | quantity | time(ms) |
|---|---|---|
| TinySTL::sort | 10万 | 11 |
| TinySTL::sort | 100万 | 133 |
| TinySTL::sort | 1000万 | 1547 |
| std::sort | 10万 | 13 |
| std::sort | 100万 | 147 |
| std::sort | 1000万 | 1730 |
####(15):directed_graph
template<class Index, class Value> using dGraph = TinySTL::directed_graph < Index, Value > ; dGraph<int, int> g; dGraph<int, int>::nodes_set_type set1, set2, set3; set1.push_back(g.make_node(1, 11)); set1.push_back(g.make_node(2, 22)); set1.push_back(g.make_node(3, 33)); g.add_node(g.make_node(0, 0), set1); set2.push_back(g.make_node(5, 55)); set2.push_back(g.make_node(6, 66)); set2.push_back(g.make_node(7, 77)); g.add_node(g.make_node(1, 11), set2); set3.push_back(g.make_node(12, 1212)); set3.push_back(g.make_node(13, 1313)); set3.push_back(g.make_node(14, 1414)); g.add_node(7, set3); g.make_edge(12, 2); g.make_edge(12, 3); g.make_edge(12, 0); std::cout << "graph after add nodes:" << std::endl; std::cout << g.to_string(); auto func = [](const dGraph<int, int>::node_type& node){ std::cout << "[" << node.first << "," << node.second << "]" << std::endl; }; std::cout << "graph DFS from node(1, 11):" << std::endl; g.DFS(1, func); std::cout << "graph BFS from node(1, 11):" << std::endl; g.BFS(1, func); std::cout << "graph after delete node(7, 77):" << std::endl; g.delete_node(dGraph<int, int>::node_type(7, 77)); std::cout << g.to_string(); ####(16):trie tree
TinySTL::trie_tree t; std::ifstream in; in.open("C:\\Users\\zxh\\Desktop\\trie_tree_test.txt"); std::vector<std::string> v; std::string s; while (in){ in >> s; v.push_back(s); } ProfilerInstance::start(); for (const auto& str : v){ t.insert(TinySTL::string(str.data())); } ProfilerInstance::finish(); std::cout << "build trie tree costs " << ProfilerInstance::millisecond() << "ms" << std::endl; ProfilerInstance::start(); auto res = t.get_word_by_prefix("v"); ProfilerInstance::finish(); std::cout << "get word by prefix \"v\" costs " << ProfilerInstance::millisecond() << "ms" << std::endl; auto i = 0; for (const auto& str : res){ ++i; if (i % 10 == 0) std::cout << std::endl; std::cout << str << " "; } std::cout << std::endl; ####(17):shared_ptr
shared_ptr<string> sp1(new string("hello")); assert(sp1.use_count() == 1); assert(*sp1 == "hello"); sp1->append(" world"); assert(*sp1 == "hello world"); { auto sp2 = sp1; assert(sp1.use_count() == 2); } assert(sp1.use_count() == 1); ####(18):unique_ptr
auto up = make_unique<string>(10, '0'); up->append("111"); assert(*up == "0000000000111"); up.release(); assert(up == nullptr); up.reset(new string("hello")); assert(*up == "hello"); ####(19):cow_ptr
cow_ptr<string> cp1 = make_cow<string>("zouxiaohang"); auto cp2 = cp1, cp3 = cp1; assert(cp1 == cp2 && cp2 == cp3); assert(*cp1 == *cp2 && *cp2 == *cp3 && *cp3 == "zouxiaohang"); string s = *cp2;//read assert(s == "zouxiaohang"); assert(cp1 == cp2 && cp2 == cp3); assert(*cp1 == *cp2 && *cp2 == *cp3 && *cp3 == "zouxiaohang"); *cp2 = ("C++");//write assert(*cp1 == *cp3 && *cp3 == "zouxiaohang"); assert(*cp2 == "C++"); ####(19):union-find set
uf_set<10> uf; uf.Union(0, 1); uf.Union(2, 3); uf.Union(3, 1); assert(uf.Find(0) == uf.Find(2)); 




