C++、Java、python中的一些常见容器总结
主要参考:《数据结构与算法/leetcode/lintcode题解》、C++参考手册、《疯狂Java》
文章目录
- <数据结构与算法>学习笔记(一)基础知识-基本数据结构
- 7.常见容器学习
- 1. C++
- 1.顺序容器
- 2.关联容器
- 3. 无序关联容器
- 4.容器适配器
- 堆
- 2. Java
- 1. Set
- 2. List集合
- 3.Queue集合
- 4. Map
- 5. Collections工具类
- 3. python
- collections
<数据结构与算法>学习笔记(一)基础知识-基本数据结构
7.常见容器学习
1. C++
参考C++参考手册,C++有一个容器库,其中包含了一些常见的数据结构。一共有三种容器:顺序容器、关联容器和无序关联容器。
顺序容器 | 关联容器 | 无序关联容器 | 容器适配器 |
---|---|---|---|
按顺序访问 | 快速查找 | 快速查找且无序 | 提供顺序容器的不同接口 |
array (c++11) | set | unordered_set(c++11起) | stack(LIFO)栈 |
vector | map | unordered_map(c++11起) | queue(FIFO)队列 |
deque | multiset | unordered_multiset(c++11起) | priority_queue(优先级) |
forward_list (c++11起) | multimap | unordered_multimap(c++11起) | |
list |
适配器是标准库中的一个通用概念,它是一中机制,使某种事物的行为看起来像另一种事物。一个容器适配器接受一种已有的容器类型,使其行为看起来像一种不同的类型。
适配器 | 要求 | 满足容器 |
---|---|---|
stack | 必须提供函数:back()、push_back()、pop_back() | vector、deque(默认)和list |
queue | back()、front()、push_back()、pop_front() | deque和list |
priority_queue | 迭代器必须满足遗留随机访问迭代器的要求,front()、push_back()、pop_back() | vector和deque |
1.顺序容器
顺序容器在C++参考手册上都有较详细的介绍,使用难度都不算大,所以不用特意做什么说明。
下面是所有的顺序容器的常用操作的示例
#include<array>
#include<iostream>
#include<string>
#include<algorithm>
#include<iterator>
#include<vector>
#include<deque>
#include <forward_list>
#include <list>
class p {private: std::string name;int id;
public:p(std::string n, int i) :name(n), id(i){}std::string getName() { return name; }int getId() { return id; }std::string toString() { std::string str = name;str.append(",id:"); str.append(std::to_string(id)); return str; }
};int main() {//----array----std::cout << "array" << std::endl;std::array<int, 3>a1{ {1,2,3} };std::array<int, 3>a2 = { 1,2,3 };std::array<std::string, 2>a3 = { "a","b" };std::sort(a1.begin(), a1.end());std::reverse_copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout, " "));std::cout << "\n";std::cout << a1.size() << std::endl;std::array<int, 10>test;test.fill(1);a3.fill("t");for (const auto& s : a3)std::cout << s << " ";//---vector---std::cout << "\nvector" << std::endl;//构造与复制std::vector<int> v1{ {1,2,3} };std::vector<int> v2(v1);std::vector<char>v3 = { 'a','b','c' };std::vector<int>v4(10, 0);//10个0std::vector<int>v5(v4.begin(), v4.end());std::vector<int>v6 = v5;std::cout << v1.front() << "---" << v1.back() << std::endl;//访问头部和尾部元素std::cout << v1[1] << std::endl;std::vector<p>ps;//添加元素与删除元素ps.emplace_back("Tom", 1);//将参数传递给元素类型的构造函数ps.push_back(p("Jerry", 2));ps.emplace(ps.begin(), "Jackey", 3);//第一个参数为容器的迭代器for (auto & c : ps)std::cout << c.toString() << std::endl;for (const auto& c : v2)std::cout << c << " ";std::cout << std::endl;v2.pop_back();//删除尾部元素for (const auto& c : v2)std::cout << c << " ";std::cout << std::endl;v2.insert(v2.begin(), 3);v2.insert(v2.begin(), 2,1);v2.insert(v2.begin(), v1.begin(), v1.end());//插入元素for (const auto& c : v2)std::cout << c << " ";std::cout << std::endl;v2.erase(v2.begin()); //删除元素v2.erase(v2.begin(), v2.begin() + 3);for (const auto& c : v2)std::cout << c << " ";std::cout << std::endl;v2.swap(v1); //交换容器for (const auto& c : v1)std::cout << c << " ";std::cout << std::endl;for (const auto& c : v2)std::cout << c << " ";std::cout << std::endl;std::cout << v1.size() << "--" << v1.max_size() << "--" << v1.capacity() << std::endl; //---deque---双端列表std::cout << "deque" << std::endl;//构造与复制std::deque<int>d1{ 1,2,3 };std::deque<int>d2 = { 1,2,3,4 };std::deque<int>d3{ {1,2,3,4,5} };std::deque<int>d4(d1);std::deque<int>d5(10, 2);std::deque<int>d6(d1.begin(), d1.begin());std::deque<int>d7;//添加与删除元素d7.assign(10, 1);for (int i : d7)std::cout << i << " ";std::cout << "/n" << d1.front() << " --" << d1.back() << std::endl;std::cout << d7.size() << "---" << d7.max_size() << std::endl;std::deque<p>d8;d8.emplace(d8.begin(), std::string("Flandre"), 1);d8.emplace_back("Remilia", 2);d8.emplace_front("Sakuya", 3);d8.push_back(p("Patchouli",4));//尾部添加d8.push_front(p("Meirin", 5));//头部for (auto c : d8)std::cout << c.toString() << std::endl;d2.insert(d2.begin(), 11);d2.insert(d2.begin(), d1.begin(), d1.end());d2.insert(d2.begin(), 3, 9);for (int i : d2)std::cout << i << " ";d2.erase(d2.begin());d2.erase(d2.begin(), d2.begin() + 4);d2.pop_back();d2.pop_front();for (int i : d2)std::cout << i << " ";d2.swap(d1);//forward_list 单链表std::cout << "\nforward_list" << std::endl;//构造与复制std::forward_list<int>f1{ 1,2,3 };std::forward_list<int>f2{ {1,2,3,4} };std::forward_list<int>f3 = { 1,2,3,4,5,6 };std::forward_list<int>f4(f1);std::forward_list<int>f6(f1.begin(), f1.end());std::forward_list<int>f7;f7.assign(5, 1);for (int i : f7)std::cout << i << " ";std::cout << std::endl;//添加与删除元素std::forward_list<p>f8;f8.emplace_front("Marisa", 2);f8.emplace_after(f8.begin(), "Reimu", 1);//如果容器为空时使用emplace_after会出错f8.push_front(p("Alice", 3));for (auto c : f8)std::cout << c.toString() << std::endl;f2.insert_after(f2.begin(), 11);f2.insert_after(f2.begin(), f1.begin(), f1.end());f2.insert_after(f2.begin(), 4, 9);std::cout << std::endl;for (auto c : f2)std::cout << c << " ";f2.pop_front();//auto it = f2.begin();//f2.erase_after(f2.begin(),++it );f2.erase_after(f2.begin());std::cout << std::endl;for (auto c : f2)std::cout << c << " ";//----list-----双链表std::cout << "\nlist" << std::endl;//构造与复制std::list<int>l1{ {1,2,3,4} };std::list<int>l2{ 1,2,3,4,5 };std::list < int > l3(l1);std::list<int>l4 = { 1,2,3,4,5,6,7 };std::list<int>l6(l1);std::list<int>l7(l6.begin(), l6.end());std::list<int>l8;l8.assign(6, 0);//添加与删除元素std::list<p>l9;l9.emplace(l9.begin(), "Kaguya", 1);l9.emplace_back("Fujiwara no Mokou", 2);l9.emplace_front("Kamishirasawa Keine", 3);l9.push_back(p("Yagokoro eirin", 4));l9.push_front(p("Reisen", 5));for (auto c : l9)std::cout << c.toString() << std::endl;l1.insert(l1.begin(), 8);l1.insert(l1.begin(), l2.begin(), l2.end());l1.sort();//排序l1.unique();//删除连续的重复元素l1.reverse();//反序l1.remove(1);//删除等于1的元素l1.remove_if([](int n) {return n > 5; });//删除大于5的元素for (auto c : l1)std::cout << c << " ";std::cout << std::endl;l1.pop_back();l1.pop_front();l1.erase(l1.begin());l1.erase(l1.begin(), --l1.end());for (auto c : l1)std::cout << c << " ";}
输出
array
3 2 1
3
t t
vector
1---3
2
Jackey,id:3
Tom,id:1
Jerry,id:2
1 2 3
1 2
1 2 3 1 1 3 1 2
1 3 1 2
1 3 1 2
1 2 3
4--1073741823--8
deque
1 1 1 1 1 1 1 1 1 1 /n1 --3
10---1073741823
Meirin,id:5
Sakuya,id:3
Flandre,id:1
Remilia,id:2
Patchouli,id:4
9 9 9 1 2 3 11 1 2 3 4 11 1 2 3
forward_list
1 1 1 1 1
Alice,id:3
Marisa,id:2
Reimu,id:11 9 9 9 9 1 2 3 11 2 3 4
9 9 9 1 2 3 11 2 3 4
list
Reisen,id:5
Kamishirasawa Keine,id:3
Kaguya,id:1
Fujiwara no Mokou,id:2
Yagokoro eirin,id:4
5 4 3 2
3
C:\Users\xhh\Source\Repos\c++study\queue_S\Debug\queue_S.exe (进程 47068)已退出,代码为 0。
按任意键关闭此窗口. . .
2.关联容器
set:含有key类型的已排序集,用比较函数进行排序。搜素、移除和插入拥有对数复杂度。set通常以红黑树来实现。
set按照键排序,所以不会出现相等的元素。
map:有序键值对容器,元素的键是唯一的,用比较函数排序键。map通常也用红黑树来实现。
mutliset
和multimap
是set和map对应的键值不唯一的,相等的键的排列顺序按照插入顺序,且不会改变。
#include<iostream>
#include<string>
#include<algorithm>
#include<iterator>
#include <set>
#include <map>
class p {private:std::string name;int id;
public:p(std::string n, int i) :name(n), id(i) {}std::string getName() { return name; }int getId() { return id; }std::string const toString() const { std::string str = name; str.append(",id:"); str.append(std::to_string(id)); return str; }constexpr bool operator<(const p& r)const { return id < r.id ; };//注意,非常重要的一步:提供内建运算符operator<重载,//这样提供了这个类的比较大小的途径,只有这样这种类的关联容器才能正常使用
};int main()
{//---set---std::cout << "---set----" << std::endl;//构造和复制std::set<int>s1{ 1,2,3 };std::set<int>s2{ {1,2,3,4,5,6,7} };std::set<int>s3 = { 1,2,3 };//std::set<int>s4(s1);//std::set<int>s5(s1.begin(), s1.end());std::set<int>s6;//没有assign函数//插入和删除元素std::set<p>s7;s7.emplace("Shameimaru Aya", 1);s7.emplace_hint(s7.begin(), "Cirno", 2);s7.insert(s7.end(), p("Youmu", 3));for (auto c : s7)std::cout << c.toString() << std::endl;s1.insert(s1.begin(), 9);s1.insert(s2.begin(), s2.end());for (auto c : s1)std::cout << c << " ";std::cout << std::endl;s1.erase(s1.begin(),++s1.begin());s1.erase(3);s1.erase(s1.begin());for (auto c : s1)std::cout << c << " ";std::cout << std::endl;std::cout << s2.count(2) << std::endl;//返回匹配特定键的元素数量std::cout << *s2.find(2) << std::endl;//寻找std::cout << *s2.equal_range(3).second << std::endl;//返回匹配特定键的元素范围,std::cout << *s2.lower_bound(4) << std::endl;//返回指向首个不小于给定键的元素的迭代器std::cout << *s2.upper_bound(5) << std::endl;//返回指向首个大于给定键的元素的迭代器//---map-----std::cout << "\nmap" << std::endl;//构造和复制std::map<int, int>m1{{1,2},{3,4}};std::map<char, int>m2{ {std::make_pair('c',1),std::make_pair('d',2)} };std::map<int, int>m3(m1);std::map<int, int>m4 = { {1,2},{3,4},{5,6},{7,8} };std::map<p, int>m5;m5.emplace(std::make_pair(p("Yuyuko",1),2));m5.emplace(std::make_pair(p("Yakumo Yukari", 2), 3));m5.emplace_hint(m5.begin(), std::make_pair(p("Suika", 4),5));m5.try_emplace(p("Tenshi", 5), 1);m5[p("Ran", 6)] = 4;for (auto c : m5)std::cout << c.first.toString() << "-->value-->" << c.second << std::endl;std::string str = "Explicit is better than implicit.";//可以将map用于统计一段字符串中的字符std::map <char, int>m6;for(auto c:str){if (m6.find(c) != m6.end())//寻找指定键值的元素,没有则返回容器的尾部迭代器end()m6[c]++;elsem6[c] = 1;}for (auto& c : m6)std::cout << c.first << ":" << c.second << " ";std::cout << std::endl;m6.erase(m6.begin());//删除迭代器指向的元素m6.erase(m6.begin(), ++m6.begin());//删除范围内的元素m6.erase('i');//删除指定键值的元素for (auto& c : m6)std::cout << c.first << ":" << c.second << " ";std::cout << std::endl;return 0;
}
输出
---set----
Shameimaru Aya,id:1
Cirno,id:2
Youmu,id:3
1 2 3 4 5 6 7 9
4 5 6 7 9
1
2
4
4
6map
Yuyuko,id:1-->value-->2
Yakumo Yukari,id:2-->value-->3
Suika,id:4-->value-->5
Tenshi,id:5-->value-->1
Ran,id:6-->value-->4:4 .:1 E:1 a:1 b:1 c:2 e:2 h:1 i:6 l:2 m:1 n:1 p:2 r:1 s:1 t:5 x:1
E:1 a:1 b:1 c:2 e:2 h:1 l:2 m:1 n:1 p:2 r:1 s:1 t:5 x:1C:\Users\xhh\Source\Repos\c++study\queue_S\Debug\queue_S.exe (进程 61628)已退出,代码为 0。
按任意键关闭此窗口. . .
3. 无序关联容器
unordered_set
:键值唯一,搜索、插入和移除具有平均常数时间复杂度。在内部元素不以特别的顺序排列,而是组织进桶中。元素被放进那个同依赖于其值的哈希。这允许对单独元素的快速访问。但不可修改容器元素。注意无序容器比较特殊,如果要用这一容器来装自定义的某个类,要么自定义一个这个类的散列函数然后再容器声明时使用,或者使用注入的std::hash特化。
#include<iostream>
#include<string>
#include<algorithm>
#include<iterator>
#include <unordered_map>
#include <unordered_set>
class p {private:std::string name;int id;
public:p(std::string n, int i) :name(n), id(i) {}const std::string getName() const{ return name; }const int getId() const { return id; }std::string const toString() const { std::string str = name; str.append(",id:"); str.append(std::to_string(id)); return str; }constexpr bool operator<(const p& r)const { return id < r.id ; };//注意,非常重要的一步:提供内建运算符operator<重载,//这样提供了这个类的比较大小的途径,只有这样这种类的关联容器才能正常使用constexpr bool operator==(const p& r)const { return id == r.id && name==r.name; }
};// std::hash 的自定义特化能注入 namespace std
//要使用无序关联容器来装这个类的话,这一步是必要的
namespace std
{template<> struct hash<p>{typedef p argument_type;typedef std::size_t result_type;result_type operator()(argument_type const& s) const{result_type const h1(std::hash<std::string>{}(s.getName()));result_type const h2(std::hash<int>{}(s.getId()));return h1 ^ (h2 << 1); // 或使用 boost::hash_combine (见讨论)}};
}int main()
{//unordered_setstd::cout << "unordered_set" << std::endl;std::unordered_set<int>us1{{1,2,3,4,5}};std::unordered_set<int>us2(us1);std::unordered_set<int>us3 = { 1,2,3,4,5,6 };//插入和删除std::unordered_set<p>us4;us4.emplace("Rumia", 1);us4.emplace_hint(us4.begin(), p("Daiyousei", 2));us4.insert(us4.begin(), p("Lily White", 3));for (auto c : us4)std::cout << c.toString() << std::endl;us3.insert(us3.begin(), 7);us3.insert(us1.begin(), us1.end());for (auto c : us3)std::cout << c << " ";std::cout << std::endl;us3.erase(us3.begin());us3.erase(3);us3.erase(us3.begin(), ++us3.begin());for (auto c : us3)std::cout << c << " ";std::cout << std::endl;std::cout << *us3.find(5) << std::endl;//桶接口std::cout << us3.bucket_count() << std::endl;//返回桶的个数std::cout << us3.bucket(6) << std::endl;//返回装着特定的元素的桶for (int i = 0; i < us3.bucket_count(); ++i)std::cout << "第" << i << "个桶有" << us3.bucket_size(i) << "个元素" << std::endl;//返回指定桶的元素数量std::cout << us3.hash_function()(111) << std::endl;//返回计算键值哈希值的哈希函数//unordered_mapstd::cout << "unordered_map" << std::endl;//构造与复制std::unordered_map<int, int>um1{ {{1,2},{2,3},{3,4}} };std::unordered_map<int, int>um2 = { {1,2},{2,4} };std::unordered_map<int, int>um3(um1);std::unordered_map<char, int>um4 = { std::make_pair('a',1),std::make_pair('b',2) };//添加与删除std::unordered_map<p, int>um5;um5.emplace(p("Suika",1),1);um5.emplace_hint(um5.begin(), p("Yuka", 2), 2);um5.insert({ p("Shikieiki Yamaxanadu",3),3 });for (auto c : um5)std::cout << c.first.toString() << ":" << c.second << std::endl;um1.insert(um2.begin(),um2.end());um1.insert({ 5,6 });um1.insert({ 7,2 });um1.insert({ 6,6 });for (auto c : um1)std::cout << c.first << ":" << c.second << std::endl;;um1.erase(1);um1.erase(um1.begin(), ++um1.begin());um1.erase(um1.begin());for (auto c : um1)std::cout << c.first << ":" << c.second << std::endl;;std::cout << um1.bucket_count() << std::endl;//返回桶的个数std::cout << um1.bucket(5) << std::endl;//返回装着特定的元素的桶for (int i = 0; i < um1.bucket_count(); ++i)std::cout << "第" << i << "个桶有" << um1.bucket_size(i) << "个元素" << std::endl;//返回指定桶的元素数量std::cout << um1.hash_function()(111) << std::endl;//返回计算键值哈希值的哈希函数return 0;
}
输出
unordered_set
Rumia,id:1
Daiyousei,id:2
Lily White,id:3
1 2 3 4 5 6 7
4 5 6 7
5
8
3
第0个桶有1个元素
第1个桶有1个元素
第2个桶有1个元素
第3个桶有1个元素
第4个桶有0个元素
第5个桶有0个元素
第6个桶有0个元素
第7个桶有0个元素
3605745226
unordered_map
Suika,id:1:1
Yuka,id:2:2
Shikieiki Yamaxanadu,id:3:3
1:2
2:3
3:4
5:6
7:2
6:6
5:6
7:2
6:6
8
0
第0个桶有1个元素
第1个桶有0个元素
第2个桶有1个元素
第3个桶有1个元素
第4个桶有0个元素
第5个桶有0个元素
第6个桶有0个元素
第7个桶有0个元素
3605745226C:\Users\xhh\Source\Repos\c++study\queue_S\Debug\queue_S.exe (进程 61952)已退出,代码为 0。
按任意键关闭此窗口. . .
4.容器适配器
stack
:栈,先进后出。
queue
:队列,先进先出
priority_queue
:优先队列,提供常数时间的最大元素查找,对数代价的插入与释出。可用用户提供的compare
更改顺序。
#include<iostream>
#include<stack>
#include <queue>
#include <vector>
#include <list>
#include <deque>int main()
{std::vector<int>v1{ {1,2,3,4} };std::deque<int>d1{ {1,2,3,4,5,6} };std::list<int>l1{ {1,2,3,4,5,6,7} };std::stack<int, std::vector<int>>s1(v1);std::stack<int, std::deque<int>>s2(d1);std::stack<int, std::list<int>>s3(l1);std::stack<int>s4(d1);std::cout << s1.top() << std::endl;std::cout << s1.size() << std::endl;s1.push(1);//向栈顶插入元素for (int i=0,j=s1.size();i<j;++i){std::cout << s1.top() << " ";//访问栈顶元素s1.pop();//删除栈顶元素}//std::queue<int, std::deque<int>>q1(d1);std::queue<int, std::list<int>>q2(l1);std::queue<int>q3(d1);q1.push(10);//向队尾插入元素q1.emplace(11);std::cout << q1.front() << std::endl;//访问第一个元素std::cout << q1.back() << std::endl;//访问最后一个元素for(int i=0,j=q1.size();i<j;++i){std::cout << q1.front() << " ";q1.pop();//删除首个元素}//std::priority_queue<int, std::vector<int>>p1(std::less<int>(),v1);std::priority_queue<int, std::deque<int>>p2(std::less<int>(),d1);std::priority_queue<int>p3(std::less<int>(),v1);//所以优先队列默认是使用容器vectorstd::cout << std::endl;p1.push(5);p1.push(3);std::priority_queue<int>p4(p3);std::cout << p1.top() << std::endl;std::cout << p1.size() << std::endl;for(int i=0,j=p1.size();i<j;++i){std::cout << p1.top() << " ";p1.pop();}std::cout << std::endl;return 0;
}
输出
4
4
1 4 3 2 1 1
11
1 2 3 4 5 6 10 11
5
6
5 4 3 3 2 1C:\Users\xhh\Source\Repos\c++study\queue_S\Debug\queue_S.exe (进程 71228)已退出,代码为 0。
按任意键关闭此窗口. . .
堆
Heap,堆,通常指二叉堆,二叉堆是一个近似完全二叉树的数据结构。子节点的键值总是小于(或者大于)它的父节点,且每个节点的左右子树又是一个二叉堆(大根堆或者小根堆)。根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或者小根堆。常用作实现优先队列。
特点:
- 以数组表示,以完全二叉树的方式理解
- 唯一能同时最优的利用时间和空间的方法
- 索引从0开始,父节点i的左子节点位置:
2*i+1
,右子节点位置2*i+2
,子节点i的父节点位置floor((i-1)/2)
基本操作:
- 最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
- 创建最大堆:将堆所有数据重新排序
- 堆排序:移除位于第一个数据的根节点,并作最大堆调整的递归运算
#pragma once
#include<algorithm>
#include<functional>
#include<stdexcept>
#include<unordered_map>
#include<utility>
#include<vector>template<typename T,typename TComparator=std::equal_to<T>,typename PComparator=std::less<double>,typename Hasher=std::hash<T>>
class maxHeap
{public:maxHeap(int m=2,const PComparator &c=PComparator(),const Hasher &hasj=Hasher(),const TComparator &tcomp=TComparator());~maxHeap();void push(double pri,const T &item);T const &top()const;void pop();bool empty()const;void decreaseKey(double newpri,const T &item);private:void trickleUp(int loc);void trickDown(int loc);std::vector<std::pair<double,T>> store_;int m_;PComparator c_;std::unordered_map<T,size_t,Hasher,TComparator>KeyTOLocation_;
};template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline maxHeap<T, TComparator, PComparator, Hasher>::maxHeap(int m, const PComparator& c, const Hasher& hash, const TComparator& tcomp):store_(),m_(m),KeyTOLocation_(100,hash,tcomp){}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline maxHeap<T, TComparator, PComparator, Hasher>::~maxHeap()
{}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline void maxHeap<T, TComparator, PComparator, Hasher>::push(double pri, const T& item)
{std::pair<double,T>temp(pri,item);store_.push_back(temp);KeyTOLocation_[item]=store_.size();trickleUp(store_.size()-1);
}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline T const& maxHeap<T, TComparator, PComparator, Hasher>::top() const
{if(empty()){throw std::logic_error("can't top an empty heap");}return store_[0].second;
}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline void maxHeap<T, TComparator, PComparator, Hasher>::pop()
{if(empty())throw std::logic_error("can't pop an empty heap");store_[0]=store_[store_.size()-1];KeyTOLocation_.erase(store_[0].second);store_.pop_back();if(empty())return;trickleUp(0);
}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline bool maxHeap<T, TComparator, PComparator, Hasher>::empty() const
{return store_.empty();
}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline void maxHeap<T, TComparator, PComparator, Hasher>::decreaseKey(double newpri, const T& item)
{std::pair<double,T>temp=store_[KeyTOLocation_[item]];temp.first=newpri;trickleUp(KeyTOLocation_[item]);
}template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline void maxHeap<T, TComparator, PComparator, Hasher>::trickleUp(int loc)
{int parent=(loc-1)/m_;while(parent>=0&&c_(store_[loc].first,store_[parent].first)){std::pair<double,T>temp=store_[loc];store_[loc]=store_[parent];store_[parent]=temp;double to_swap=KeyTOLocation_[store_[loc].second];KeyTOLocation_[store_[loc].second]=KeyTOLocation_[store_[parent].second];KeyTOLocation_[store_[parent].second]=to_swap;loc=parent;parent=(loc-1)/m_;}
}
template<typename T, typename TComparator, typename PComparator, typename Hasher>
inline void maxHeap<T, TComparator, PComparator, Hasher>::trickDown(int loc)
{if(loc*m_+1>store_.size()-1)return;int smallerChild=m_*loc+1;for(size_t i=0;i<m_;++i){if(m_*loc+i<store_.size()){int rChild=m_*loc+i+1;if(c_(store_[rChild].first,store_[smallerChild].first)){smallerChild=rChild; }}}if(c_(store_[smallerChild].first,store_[loc].first)){std::pair<double,T>temp=store_[loc];store_[loc]=store_[smallerChild];store_[smallerChild]=temp;double to_swap=KeyTOLocation_[store_[loc].second];KeyTOLocation_[store_[loc].second]=to_swap;trickDown(smallerChild);}
}
main.cpp
#include"maxHeap.h"
#include<iostream>
int main(){maxHeap<int>heap;heap.push(0.3,10);heap.push(0.1,22);heap.push(0.5,123);heap.push(0.8,12);while(!heap.empty()){std::cout<<heap.top()<<std::endl;heap.pop();}return 0;}
2. Java
参考:《疯狂Java讲义》、Java官方文档
Java集合类主要有:Set、Queue、List、Map四种体系。和C++中的相关的容器类相对应,用途大概都能想到,但实际用法和C++还是有很大区别的,毕竟是不同的语言。Java的集合类主要由两个接口派生而来:Collection
、Map
,他们是集合框架的根接口,两个接口又包含一些子接口或实现类。它们的继承树分别如下:
这些集合类定义在Java.Base
模块下的Java.util
包下。Java.util
包的官方简介如下:
Contains the collections framework, some internationalization support classes, a service loader, properties, random number generation, string parsing and scanning classes, base64 encoding and decoding, a bit array, and several miscellaneous utility classes. This package also contains legacy collection classes and legacy date and time classes.
Collection
和Map
都是泛型接口。当然,Java里面实例化泛型类时可以不用尖括号显示指定类型,这样一般容器中元素的类型都是Object
的,这样虽然没有语法错误,但IDEA会给出警告的,因为这样可能会出现一些问题,一般还是用棱形语法指定容器内元素类型比较好。
首先是Collection接口的通用的一些方法:
package algo_study;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;public class collectionStudy {public static void main(String[] args) {Collection test=new ArrayList();test.add(122);test.add(1232);test.add(11);System.out.println("test集合的元素个数"+test.size());test.remove(122);test.add('a');test.add("adfs");test.forEach(obj->System.out.println("->"+obj));//用Lambda表达式遍历集合中的元素for(Iterator c = test.iterator();c.hasNext();) {//用迭代器遍历集合中的元素Object o = c.next();System.out.println(o);if (o.equals(11)) {c.remove();}}Iterator it=test.iterator();it.forEachRemaining(obj->System.out.println("-"+obj));//用迭代器提供的forEachRemaining方法的lambda来遍历Object[] oo=test.toArray();System.out.println(oo[0]);System.out.println(cal(test,ele->ele.equals('a')));//用stream来操作集合System.out.println(test.stream().filter(ele->ele.toString().length()>1).count());}public static int cal(Collection c, Predicate p){//利用Predicate来操作集合int t=0;for(Iterator it=c.iterator();it.hasNext();){if(p.test(it.next())){t++;}}return t;}
}
输出
test集合的元素个数3
->1232
->11
->a
->adfs
1232
11
a
adfs
-1232
-a
-adfs
1232
1
2
主要的是一些遍历结合元素的方法:用foreach
结合lambda表达式、用迭代器遍历、用Predicate
操作、用Stream
操作集合。
1. Set
Set接口不允许添加相同的元素,其它基本与Collect相同。而HashSet
是它的典型实现,通常用HashSet来作为Set的实现类。
HashSet的特点:
- 元素的顺序不与添加顺序相同
- 不是同步的,多个线程同时访问时需要通过代码保证其同步
- 集合元素可以是null
HashSet集合存入一个元素时会调用对象的hashCode()
方法来得到其hashCode
值,然后根据该值决定对象在HashSet中的存储位置。如果有两个值通过equals()
方法返回true,但它们的hashCode()
返回值不同,还是可以添加成功,被储存在不同位置。所以集合实际上在添加元素时同时做出两个判断:通过equals
方法来判断新加入的元素是否和已有的元素相等、计算新加入的元素的hashCode值确定已有元素的hashCode是否存在和它相等的。这时会存在几种情况:如果新加入的元素–equals方法返回true且hashCode相同则添加失败、equals返回true但hashCode不同则添加成功、equals返回false且hashCode不同则添加失败、equals返回false但hashCode相同–>这时HashSet会试图将它们保存在同一个位置,会在这个位置用链式结构来保存多个对象,这样会导致HashSet的新能降低的,所以应尽量避免出现这种情况。如下
package algo_study;import java.util.*;
import java.util.function.Predicate;class test{public boolean equals(Object obj){return false;}public int hashCode(){return s.hashCode();}test(int i,String s){this.id=i;this.s=s;}private int id;private String s;
}
public class collectionStudy {public static void main(String[] args) {test t=new test(1,"test");Set<test> s=new HashSet<>();s.add(t);System.out.println(s.add(new test(2,"test")));//trueSystem.out.println(s.add(new test(2,"testt")));//true}
}
LinkedHashSet
是HashSet的子类,它同时用链表来维护元素的次序,这样,遍历时它会按元素的添加顺序来访问集合的元素,虽然维护插入顺序会降低它的性能,但遍历元素时它具有更好的性能。
TreeSet
是SortedSet
接口的实现类。它确保集合元素处于排序状态。相比较HashSet它提供了一些额外的方法。TreeSet
是采用红黑树的数据结构来存储集合元素,我们知道红黑树是需要比较两个元素的大小的,它支持两种排序方法:自然排序
和定制排序
,默认采用自然排序。
自然排序
:调用元素的compareTo(Object o)
方法来比较元素之间的大小,然后将元素按升序排列。该方法返回一个int类型,相等则返回0,小于则返回负整数,大于则返回正整数。
Java提供了一个Comparable
接口,该接口中定义了compareTo(Object o)
的方法,相当于定义了一个规范。所以如果要让TreeSet
的元素为自定义的类型,简单的做法是让这个自定义的类型实现Comparable
接口,如果该类没有实现Comparable接口,添加元素时会引发ClassCaseException
异常。Java中常用的一些类自然是实现了该接口的,如:BigDecimal
、BigInteger
、Character
、Boolean
、String
、Date
、Time
等。
定制排序
:自然排序时这个类型通过实现Comparable接口实现,如果不想让类实现Comparable接口,也可以在实例化TreeSet对象时提供一个Comparator
对象与TreeSet集合关联,可以用Lambda表达式来代替Comparator。
这两种排序选择其中一种就行了。
EnumSet
类:枚举类的集合类。其中的元素都是指定的枚举类型的枚举值。EnumSet的集合元素是有序的,以枚举值在枚举类中的定义顺序来决定集合元素的顺序。EnumSet内部通过位向量的形式来存储,它占用内存小,运行效率高,尤其在进行批量操作时。
EnumSet不允许插入null元素。
注意:上面介绍的Set的三个实现类HashSet、TreeSet、EnumSet都是线程不安全的,为此,可以通过Collections
工具类中的synchronizedSortedSet
方法来包装该Set集合。
SortedSet s=Collections.synchronizedSortedSet(new TreeSet(...));
上面介绍的几个实现类的实例如下:
package algo_study;import java.util.*;
import java.util.function.Predicate;class test {//implements Comparablepublic boolean equals(Object obj){return true;}public boolean equals(test t){return id==t.id && s.equals(t.s);}public int hashCode(){return s.hashCode();}test(int i,String s){this.id=i;this.s=s;}public String toString(){return "id:"+this.id+" name:"+this.s;}private int id;private String s;public int getId(){return id;}/*@Overridepublic int compareTo(Object o) {test t=(test)o;if(id<t.id)return -1;if(id>t.id)return 1;return 0;}*/
}
enum Week{Monday,Tuesday,Wednesday,Thursday,Firday,Saturday,Sunday
}//一个枚举类
public class collectionStudy {public static void main(String[] args) {test t=new test(1,"test");//HashSetSet<test> s=new HashSet<>();s.add(t);System.out.println(s.add(new test(2,"test")));System.out.println(s.add(new test(2,"testt")));System.out.println(s);s.forEach(o->System.out.println(o));//LinkedHashSetSet<test> s1=new LinkedHashSet<>();s1.add(t);s1.add(new test(3,"testt"));s1.add(new test(2,"testtt"));s1.add(new test(3,"tttt"));System.out.println(s1);//TreeSetTreeSet<test> s2=new TreeSet<>((o1,o2)->{test m1=(test)o1;test m2=(test)o2;return m1.getId()<m2.getId()?-1:m1.getId()>m2.getId()?1:0;});//Lambda表达式s2.add(t);System.out.println(s2.add(new test(2,"ttest")));System.out.println(s2.add(new test(0,"tests")));System.out.println(s2.add(new test(4,"ttt")));System.out.println(s2);System.out.println(s2.first());System.out.println(s2.last());System.out.println(s2.lower(t));System.out.println(s2.higher(t));System.out.println(s2.comparator());System.out.println(s2.subSet(t,s2.last()));//返回子集System.out.println(s2.headSet(t));//返回子集包含t之前的元素System.out.println(s2.tailSet(t));//返回子集包含t之后的元素//EnumSetEnumSet<Week> ew=EnumSet.allOf(Week.class);System.out.println(ew);EnumSet<Week>ew1=EnumSet.noneOf(Week.class);ew1.add(Week.Firday);ew1.add(Week.Monday);System.out.println(ew1);EnumSet<Week>ew2=EnumSet.of(Week.Monday,Week.Firday);System.out.println(ew2);EnumSet<Week>ew3=EnumSet.range(Week.Thursday,Week.Saturday);System.out.println(ew3);EnumSet<Week>ew4=EnumSet.complementOf(ew3);System.out.println(ew4);}
}
false
true
[id:2 name:testt, id:1 name:test]
id:2 name:testt
id:1 name:test
[id:1 name:test, id:3 name:testt, id:2 name:testtt, id:3 name:tttt]
true
true
true
[id:0 name:tests, id:1 name:test, id:2 name:ttest, id:4 name:ttt]
id:0 name:tests
id:4 name:ttt
id:0 name:tests
id:2 name:ttest
algo_study.collectionStudy$$Lambda$2/1747585824@3d075dc0
[id:1 name:test, id:2 name:ttest]
[id:0 name:tests]
[id:1 name:test, id:2 name:ttest, id:4 name:ttt]
[Monday, Tuesday, Wednesday, Thursday, Firday, Saturday, Sunday]
[Monday, Firday]
[Monday, Firday]
[Thursday, Firday, Saturday]
[Monday, Tuesday, Wednesday, Sunday]
2. List集合
List集合:有序、可重复集合,可通过索引访问指定位置的元素。
ArrayList
和Vector
是List
接口的两个典型实现。ArrayList更常用一些。二者的显著区别是:ArrayList是线程不安全的,而Vector是线程安全的。所以Vector的新能更低一些。然而即使需要一个线程安全的List集合,也不推荐用Vector而是用Collections
工具类将一个ArrayList变成线程安全的。
Vector
提供了一个Stack
子类,用于模拟栈:peek()
显示第一个元素、pop()
弹出第一个元素、push()
将一个元素进栈。(线程安全的)。同样由于性能较差,不推荐用,取而代之的是ArrayDeque
。
package algo_study;import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;public class listStudy {public static void main(String[] args) {//ListList l=new ArrayList();l.add("元素1");l.add("元素2");l.add("element 3");System.out.println(l);l.add(0,"element4");System.out.println(l);for(int i=0;i<l.size();++i){System.out.println(l.get(i));//通过索引访问元素,Java中并不能重载操作符,所以不能像C++中利用中括号}System.out.println(l.indexOf("element 3"));l.remove(2);System.out.println(l);System.out.println(l.subList(1,l.size()));l.set(0,"ele 0");System.out.println(l);l.sort((e1,e2)->{return e1.toString().length()-e2.toString().length() ;});//排序System.out.println(l);l.replaceAll(ele->ele.toString().length());System.out.println(l);//ArrayListArrayList<String>a1=new ArrayList<>();a1.add("tetst");a1.add("ele1");a1.add("ele2");a1.add(1,"ele3");System.out.println(a1);a1.remove(1);System.out.println(a1);a1.set(1,"test");System.out.println(a1);ListIterator it=a1.listIterator();while(it.hasNext()){//用迭代器遍历System.out.println(it.next());}while(it.hasPrevious()){System.out.println(it.previous());//反向遍历}//固定长度的ListList<String>l1=Arrays.asList("test","ele");System.out.println(l1);//l1不允许添加删除元素}
}
输出
[元素1, 元素2, element 3]
[element4, 元素1, 元素2, element 3]
element4
元素1
元素2
element 3
3
[element4, 元素1, element 3]
[元素1, element 3]
[ele 0, 元素1, element 3]
[元素1, ele 0, element 3]
[3, 5, 9]
[tetst, ele3, ele1, ele2]
[tetst, ele1, ele2]
[tetst, test, ele2]
tetst
test
ele2
ele2
test
tetst
[test, ele]
3.Queue集合
Queue
接口模拟队列,它有一个PriorityQueue
实现类,它还有一个Deque
接口,代表一个双端队列,可同时从两端添加删除元素。Deque
的实现类即可以当成队列使用也可以当成栈来使用。两个实现类:ArrayDeque
和LinkedList
。
PriorityQueue
会按元素的大小将元素排序。
Deque方法对比:
Queue | Deque | Stack | Deque |
---|---|---|---|
add、offer | addLast、offerLast | push | addFirst、offerFirst |
remove、poll | removeFirst、pollFirst | pop | removeFirst、pollFirst |
element、peek | getFirst、peekFirst | peek | getFirst、peekFirst |
ArrayDeque内部以数组的形式来保存元素,所以随机访问集合时有比较好的性能。而LinkedList内部以链表的形式来保存集合中的元素,所以随机访问集合元素时性能差,但插入删除元素时性能很好。另外Vector也是以数组形式存储元素的,但它实现线程同步同时实现机制不好导致各方面性能都不好。
实际使用时自然是根据实际需求灵活选择那个容器。如果不知道选择那个时就选ArrayList
就行了。
package algo_study;import java.util.ArrayDeque;
import java.util.LinkedList;
import java.util.PriorityQueue;public class QueueLearn {public static void main(String[] args) {//PriorityQueuePriorityQueue p1=new PriorityQueue();p1.offer(1);p1.offer(4);p1.offer(-2);p1.offer(4);System.out.println(p1);System.out.println(p1.poll());//ArrayDeque//模拟栈,后进先出ArrayDeque st=new ArrayDeque();st.push(1);//或者addFirst,入栈st.push(2);st.push(4);st.push(6);System.out.println(st);System.out.println(st.peek());//显示栈顶元素while(st.size()!=0){System.out.println(st.pop());//出栈}//模拟队列ArrayDeque que=new ArrayDeque();que.add(123);//入队que.offer(112);//入队que.add(23);que.add(122);System.out.println(que);System.out.println(que.element());//显示队首元素System.out.println(que.peek());//显示队首元素System.out.println(que.remove());//出队while(que.size()!=0){System.out.println(que.poll());//出队}//LinkedList//栈,和ArrayList的方法名相同,还是很不错的LinkedList sta=new LinkedList();sta.push(11);sta.push(22);sta.push(2);sta.push(4);sta.push(6);System.out.println(sta);System.out.println(sta.peek());//显示栈顶元素while(st.size()!=0){System.out.println(sta.pop());//出栈}//队列,ArrayDeque quel=new ArrayDeque();quel.add(123);//入队quel.offer(112);//入队quel.add(23);quel.add(122);System.out.println(quel);System.out.println(quel.element());//显示队首元素System.out.println(quel.peek());//显示队首元素System.out.println(quel.remove());//出队while(que.size()!=0){System.out.println(quel.poll());//出队}}
}
输出
[-2, 4, 1, 4]
-2
[6, 4, 2, 1]
6
6
4
2
1
[123, 112, 23, 122]
123
123
123
112
23
122
[6, 4, 2, 22, 11]
6
[123, 112, 23, 122]
123
123
123
4. Map
Map
接口下有:HashMap
、LinkedHashMap
、SortedMap
(接口)、TreeSet
、EnumSet
等子接口和实现类,正好是和Set
对应的,这样正好方便我们去理解这些子接口和实现类。
HashMap和Hashtable都是HashMap接口的典型实现类,它们的区别类似于ArrayList和Vector。
Hashtable类有个子类为Properities
,可以用来读写属性文件,这个类挺有用的。
而WeakHashMap
与HashMap用法相似,区别在于WeakHashMap对象的key只保留对实际对象的弱引用。
IdentityHashMap
与HashMap也相似,但它处理两个key相等时仅当两个key严格相等时才认为它们相等。
package algo_study;import java.io.*;
import java.util.*;class mapTest{private int id;private String name;public int getId(){return id;}public String getName(){return name;}@Override//对于HashMap来说必须要重载equals和hashCode这两个方法,顺便重载toStringpublic boolean equals(Object o){mapTest m=(mapTest)o;return id==m.getId() && name.equals(m.getName());}@Overridepublic int hashCode() {return this.toString().hashCode();}@Overridepublic String toString(){return "id->"+id+"&& name->"+name;}public mapTest(int i,String s){this.id=i;this.name=s;}
}public class mapLearn {public static void main(String[] args) throws IOException {//HashMapHashMap hm=new HashMap();hm.put(new mapTest(10,"Tom"),1212);hm.put(new mapTest(11,"Jack"),21212);mapTest m=new mapTest(111,"Joker");hm.put(m,111);hm.put(m,12112);hm.put(m,123);//放入重复的key会覆盖原有的Value。System.out.println(hm);System.out.println(hm.put(m,11111));//如果覆盖原有值时会返回被覆盖的值System.out.println(hm.containsKey(m));System.out.println(hm.containsValue(1212));for(Object k:hm.keySet()){System.out.println(k+"---->"+hm.get(k));//遍历}hm.forEach((k,v)->System.out.println(k+"->"+v));//用forEach时有两个参数,key和valueHashMap<mapTest, Integer>mi=new HashMap<>();hm.forEach((k,v)->mi.put((mapTest) k,(int)v));System.out.println(mi);//Properities类,这个类是Hashtable的子类,用于读写属性文件,非常有用的类//Properties properties=new Properties();properties.setProperty("name","XieHuiHui");properties.setProperty("QQ","0000000000");properties.setProperty("phone number","00000000000000");properties.store(new FileOutputStream("test.ini"),"coment line");//写入属性文件Properties pro2=new Properties();File f=new File("test.ini");System.out.println(f.exists());pro2.load(new FileInputStream("test.ini"));//读取属性文件System.out.println(pro2);System.out.println(pro2.get("QQ"));//LinkedHashMapLinkedHashMap<mapTest,Integer>lmi=new LinkedHashMap<>();lmi.put(m,111);lmi.put(new mapTest(11,"sss"),11);lmi.put(new mapTest(12313,"sdfa"),1231);System.out.println(lmi);//TreeMapTreeMap<mapTest,Integer>tmi=new TreeMap<>((o1,o2)->{mapTest t1=(mapTest) o1;mapTest t2=(mapTest)o2;return o1.getId()-o2.getId();});//定制排序tmi.put(m,111);tmi.put(new mapTest(1,"2w324"),12);tmi.put(new mapTest(123,"sadfs"),2);System.out.println(tmi);//identityHashMapIdentityHashMap id=new IdentityHashMap();id.put(m,111);id.put(new mapTest(1,"aaa"),12);id.put(new mapTest(123,"sadfs"),2);id.put(new mapTest(1,"aaa"),12);System.out.println(id);//EnumMapEnumMap<Week,String> en=new EnumMap(Week.class);en.put(Week.Monday,"周一");en.put(Week.Tuesday,"周二");System.out.println(en);}
}
{id->111&& name->Joker=123, id->11&& name->Jack=21212, id->10&& name->Tom=1212}
123
true
true
id->111&& name->Joker---->11111
id->11&& name->Jack---->21212
id->10&& name->Tom---->1212
id->111&& name->Joker->11111
id->11&& name->Jack->21212
id->10&& name->Tom->1212
{id->111&& name->Joker=11111, id->11&& name->Jack=21212, id->10&& name->Tom=1212}
true
{phone number=00000000000000, name=XieHuiHui, QQ=0000000000}
0000000000
{id->111&& name->Joker=111, id->11&& name->sss=11, id->12313&& name->sdfa=1231}
{id->1&& name->2w324=12, id->111&& name->Joker=111, id->123&& name->sadfs=2}
{id->111&& name->Joker=111, id->1&& name->aaa=12, id->123&& name->sadfs=2, id->1&& name->aaa=12}
{Monday=周一, Tuesday=周二}
5. Collections工具类
- 改变List元素次序的方法:
- void reverse(List list)
- void shuffle(List list): 对list集合元素进行随机排序(模拟“洗牌”行为)
- void sort(List list):根据元素的自然排序对集合元素进行升序
- void sort(List list,Comparator c):根据指定的Comparator排序
- void swap(List list ,int i,int j):将i处元素和j处元素进行交换
- void rotate(List list,int distance):distance为正时,将结合后distance个元素整体移动到前面,否则将前distance个元素整体移动到后面
- 查找、替换操作
- int binarySearch(List,list,Object key):用二分法搜索指定的List集合,返回指定对象的索引,必须确保List中元素处于有序状态
- Object max(Collection coll):根据元素自然排序返回集合中的最大元素
- Object max(Collection co,Comparator c):~
- Object min(Collection co)
- Object min(Collection co,Comparator c)
- void fill(List l,Object o):用指定元素O替换集合中的所有元素
- int frequency(Collection c,Object O):返回O的出现次数
- int indexOfSubList(List source,List target):返回子List对象在父List中首次出现的位置,没有则返回-1
- boolean replaceAll(List list,Object oldVal,Object newVal):用一个新值替换所有的旧值
- 同步控制:
synchronizedXXX()
方法
package algo_study;import java.util.*;public class collectionsLearn {public static void main(String[] args) {//改变List中元素次序的操作List l=new ArrayList();l.add(11);l.add(22);l.add(1);l.add(23);System.out.println(l);Collections.reverse(l);System.out.println(l);Collections.shuffle(l);System.out.println(l);Collections.sort(l);System.out.println(l);Collections.sort(l,(o1,o2)->{int i1=(int)o1;int i2=(int)o2;return i2-i1;});System.out.println(l);Collections.swap(l,0,1);System.out.println(l);Collections.rotate(l,2);System.out.println(l);//查找、替换l.add(2);l.add(4);Collections.sort(l);System.out.println(l);System.out.println(Collections.binarySearch(l,4));//二分法搜索System.out.println(Collections.max(l));System.out.println(Collections.min(l));List l2=new ArrayList(l);Collections.fill(l2,2);System.out.println(l2);l.add(1);System.out.println(Collections.frequency(l,1));System.out.println(Collections.indexOfSubList(l,l2));System.out.println(Collections.replaceAll(l,1,2));System.out.println(l);//同步控制,下面创建的几个对象都是线程安全的List l3=Collections.synchronizedList(new ArrayList<>());Set s=Collections.synchronizedSet(new HashSet<>());Map m=Collections.synchronizedMap(new HashMap<>());}
}
[11, 22, 1, 23]
[23, 1, 22, 11]
[11, 22, 23, 1]
[1, 11, 22, 23]
[23, 22, 11, 1]
[22, 23, 11, 1]
[11, 1, 22, 23]
[1, 2, 4, 11, 22, 23]
2
23
1
[2, 2, 2, 2, 2, 2]
2
-1
true
[2, 2, 4, 11, 22, 23, 2]
3. python
前面可以看出Java和C++的容器类不管时用途还是用法都是比较类似的,也都有很多细节需要注意。而python的容器就显得和不一样。
python内置的容器主要有三个list
、tuple
、dict
,这三个list最常用,我反正能用list的基本都用list,list本身很随意,可以任意添加元素,元素也可以是不同类型的,元素也可以是list、tuple、dict。
要说对应的化,list可勉强对应vector,tuple为不可变集合,dict可对应map。
- list
通过help(list)
可以注意到list类自身有以下常见的方法:
- append
- clear
- copy
- count
- extend
- index
- insert
- pop
- remove
- reverse
- sort
- tuple
- dict
dict中的函数有
- clear
- copy
- get
- items
- keys
- pop
- popitem
- setdefault
- update
- values
python中通过heapq的lib来实现priority queue。
队列和栈都可以通过list来实现,既然list通用性这么强,效率自然是有所牺牲的。为了提升数据的处理效率,一些高效的数据结构放在了collections
中。如deque
类。
collections
官方文档中的描述为:
This module implements specialized container datatypes providing alternatives to Python's general purpose built-in containers, dict,list, set, and tuple.
主要有以下的一些包装类
* namedtuple factory function for creating tuple subclasses with named fields* deque list-like container with fast appends and pops on either end* ChainMap dict-like class for creating a single view of multiple mappings* Counter dict subclass for counting hashable objects* OrderedDict dict subclass that remembers the order entries were added* defaultdict dict subclass that calls a factory function to supply missing values* UserDict wrapper around dictionary objects for easier dict subclassing* UserList wrapper around list objects for easier list subclassing* UserString wrapper around string objects for easier string subclassing
具体的一些用法自己摸索完全没问题的。这个类的意义就是提供一些更高效的容器,当然可能用起来不如内置的容器方便,但可以确定的是当我们更注重运行效率而不是自己的开发效率时最好首先考虑使用collections类中的元素,这时再不用的话其它时候更用不到了。
C++、Java、python中的一些常见容器总结相关推荐
- python中的几个容器--入门--小总结
---------------------------------------------list(列表)----------------------------------------------- ...
- python中字符串的常见操作方法
1. 字符串概念,字符串是一个容器,包含若干个字符并按照一定的顺序组织成一个整体.字符串支持索引操作. 2. 创建字符串基本语法 变量名 = "字符串信息" 变量名 = '字符串信 ...
- Java面试中,一些常见的有关多线程问题!
面试作为入职的第一道门槛,其重要性不言而喻.对于从事IT的很多工作人员而言,对面试往往信心不足,毕竟在真实面试中,会遇到很多技术问题,万一哪块技术点不熟,就会与心仪的offer失之交臂.接下来,小千以 ...
- Java RestTemplate中几种常见的请求方式
在REST接口的设计中,利用RestTemplate进行接口测试是种常见的方法.本文主要从以下四个方面来看RestTemplate的使用: GET请求 POST请求 PUT请求 DELETE请求 OK ...
- java代码审计中的一些常见漏洞及其特征函数
文章来源:https://xz.aliyun.com/t/1633 最近在先知上看到之前有篇关于java代码审计的文章总结的蛮好,记录以下特征函数,方便查阅,同时自己也会将在平时代码审计过程中积累的函 ...
- JAVA数组中五种常见排序方法
前言: 几种常用的JAVA数组排序方法的整合. 法一:Arrays.sort() Arrays.sort()排序方法在java中是最简单且最常用的排序方法 int []arr1= {45,34,59, ...
- Python中函数的常见操作(创建、调用、递归函数等等)【非常详细】
- python中循环结构分有,python常见循环结构有哪些
1.for-in- 该格式在python中是最为常见的一种格式,使用极为广泛.格式:for 参数 in 循环体: pass 在上面的格式中,有很多内容可以作为循环体,比如元组.列表.字符串等等.只要能 ...
- java 绑定微信号开发_Java开发中的更多常见危险信号
java 绑定微信号开发 在< Java开发中的常见危险信号>一文中,我研究了一些不一定本身就是错误或不正确的做法,但它们可能表明存在更大的问题. 这些"红色标记"类似 ...
最新文章
- OpenCV 【十三】矩阵的掩码操作
- 多线程 python layer_在Caffe中加Python Layer的方法
- python -lambda表达式的用法
- bigint在java中用什么表示_为什么说开车最能看出一个人的人品和情商?这几条说的太精辟了...
- 青年教师大讲堂 计算机,浙海大青年教师大讲堂之船机学院“知识改变命运”...
- 2019-06-19 阿里巴巴三面
- MAKEWORD,MAKELONG,LOWORD,HIWORD,LOBYTE,HIBYTE 的使用
- 《鸟哥 Linux 私房菜》560 页新书首发!完整中文版 PDF 下载
- linux 打开权限不够,linux无法打开目录提示权限不够
- 模糊提取器(Fuzzy Extractor)
- 树——牛客网刷题第二波
- 关于Palantir ——第六部分 – 图分析应用
- win10驱动开发16——派遣函数(直接方式读操作)
- linux mysql 僵尸进程_linux shell中清理僵尸进程
- pushpush(双向队列/列表)
- 机架服务器最多有多少cpu,小身材却有大能量:高密度机架服务器
- 2021-2027全球与中国梨花油市场现状及未来发展趋势
- ubuntu 下安装fetion
- 浅谈关于quill在vue中的使用
- 《弟子规》 -- 欢迎转账,功德无量。