6.5-数据结构&算法-标准模板STL/STL容器/向量
一、标准模板库(STL)
1.定义了一系列的容器模板,实现泛型化的数据结构。
1)向量(vector),内存连续,支持下标访问和随机迭代,只有在尾部进行插入和删除效率才比较高。
2)列表(list),内存不连续,不支持下标访问和随机迭代,在任何位置进行插入和删除效率都很高。
3)双端队列(deque),内存连续,支持下标访问和随机迭代,在首尾两端进行插入和删除效率都比较高。
以上三种合称为线性容器。
4)堆栈(stack),后进先出
5)队列(queue),先进先出
6)优先队列(priority_queue),优者先出
以上三种合称为适配器容器,通过某种线性容器适配。
7)映射(map),键值对(KVP)的集合,按键升序,键唯一。
8)集合(set),没有值只有键的映射。
9)多重映射(multimap),允许重复键的映射。
10)多重集合(multiset),没有值只有键的多重映射。
以上四种合称为关联容器。通过有序树表达数据的关联性。
2.泛型函数
template<typename T>
void swap (T& a, T& b) {
T c = a;
a = b;
b = c;
}
template<typename IT>
void print (IT begin, IT end) {
while (begin != end)
cout << *begin++ << ' ';
cout << endl;
}
int a[5] = {1, 2, 3, 4, 5};
print (a, a + 5);
List list;
list.push_back (...);
...
print (list.begin (), list.end ());
3.实用工具
auto_ptr
string
pair
二、STL容器共性
1.所有的容器都支持拷贝构造和拷贝赋值,可以完整意义上的容器对象副本。
2.所有的容器都支持“==”运算符。容器的相等:容器的类型相同,容器中元素的类型相同,容器中元素的个数相等,对应元素还要满足相等性的判断。
3.容器中元素都是放入源对象拷贝。
int b;
int a[3];
a[0] = b;
4.容器中元素需要支持完整的拷贝语义。auto_ptr不适合放在容器中使用。
5.如果需要对容器的元素进行排序或者查找操作,该元素的类型还需要支持“<”和“==”操作符。
三、向量(vector)
1.基本特点
1)连续内存和下标访问
2)动态内存管理
int a[10];
int *b = new int[10];
3)通过预分配内存空间减小动态内存管理的额外开销
4)可以再随机位置做插入和删除,但只有在接近尾部的操作才是高效的。
2.定义变量
#include <vector>
using namespace std;
vector<int> vi;
vector<string> vs;
3.迭代器
vector<...>::iterator - 正向迭代器
vector<...>::const_iterator - 常正向迭代器
vector<...>::reverse_iterator - 反向迭代器
vector<...>::const_reverse_iterator - 常反向迭代器
向量的四种迭代器都是随机迭代器,可以和整数做加减运算。
通过vector<...>调用,begin()返回起始迭代器,end()返回终止迭代器,最后一个元素的下一个位置。rbegin()返回起始反向迭代器,rend()返回终止反向迭代器。
通过const vector<...>&/*调用以上函数,返回的将是const_iterator/const_reverse_interator。
4.预分配和初始化
vector<int> vi (10);
将vi初始化10个int元素,初始值为0。
vector<类> vc (10);
将vi初始化10个类类型的元素,通过无参构造函数初始化。
vector<int> vi (10, 8);
将vi初始化10个int元素,初始值为8。
vector<类> vc (10, 类 (...));
将vi初始化10个类类型的元素,通过拷贝构造函数初始化。
5.size()/resize()/clear()/capacity()/reserve()
size() - 获取元素个数,而不是容量。
resize() - 增减元素的个数,增引发构造,减引发析构。如果在新增元素时发现当前容量不够,自动扩容。但是在减少元素时不会自动收缩容量。
clear() - 清空所有的元素,导致析构。同样不会自动收缩容量。
capacity() - 获取容量,以元素为单位。
reserve() - 手动扩容。新增部分不做初始化。
6.insert()/erase()/sort()/find()
insert()/erase() - 根据迭代器参数做插入和删除。
sort()/find() - 全局算法函数,排序(快速)和查找
7.类类型对象的向量
1)无参构造
2)拷贝构造
3)拷贝赋值
4)operator==:find
5)operator</operator基本类型/比较器
练习:编写程序读取m.dat中的电影票房记录,找出票房前十名,按票房从高到低的顺序写入另一文件中。
四、双端队列(deque)
1.连续内存,下标访问和随机迭代,在首尾两端都可以进行高效的增删。
2.因为要维护首尾两端的开放性,因此双端队列和向量相比,其空间和时间复杂度要略高一些。
3.比vector多了push_front/pop_front,少了reserve。
五、列表(list)
front/back
push_front/pop_front
push_back/pop_back
insert/erase/remove
size
1.sort
2.unique - 将连续出现的相同元素唯一化。
23 35 35 35 60 12 35 35 99 35 22
|unique
V
23 35 60 12 35 99 35 22
3.splice - 将参数链表的部分或全部剪切到调用链表的特定位置。
void splice (
iterator pos,
list& lst);
list1.splice (pos, list2);
将list2中的全部数据剪切到list1的pos处。
void splice (
iterator pos,
list &lst,
iterator del);
将list2中del所指向数据剪切到list1的pos处。
void splice (
iterator pos,
list& lst,
iterator start,
iterator end );
将list2中start和end之间的数据剪切到list1的pos处。
class.cpp
#include <vector> #include <algorithm> #include "print.h" class A { public: A (int i = 0) : m_i (i) { cout << "无参构造:" << this << endl; } A (const A& that) : m_i (that.m_i) { cout << "拷贝构造:" << &that << "->" << this << endl; } A& operator= (const A& that) { cout << "拷贝赋值:" << &that << "->" << this << endl; if (&that != this) m_i = that.m_i; return *this; } ~A (void) { cout << "析构函数:" << this << endl; } operator int& (void) { return m_i; } /* operator const int& (void) const { return static_cast<int&> ( const_cast<A&> (*this)); } */ bool operator== (const A& that) const { return m_i == that.m_i; } /* bool operator< (const A& that) const { return m_i < that.m_i; } */ bool operator() (const A& a, const A& b) const { return a.m_i < b.m_i; } private: int m_i; }; int main (void) { cout << "---- 1 ----" << endl; vector<A> va (3); cout << "---- 2 ----" << endl; va.push_back (A ()); cout << "---- 3 ----" << endl; va.erase (va.begin ()); cout << "---- 0 ----" << endl; va[0] = A (10); va[1] = A (50); va[2] = A (70); va.push_back (A (60)); vector<A>::iterator it = find (va.begin (), va.end (), A (70)); if (it == va.end ()) cout << "没找到!" << endl; else cout << "找到了:" << *it << endl; // sort (va.begin (), va.end ()); sort (va.begin (), va.end (), va[0]); print (va.begin (), va.end ()); return 0; }
deque.cpp
#include <deque> #include <algorithm> #include "print.h" int main (void) { deque<int> di; di.push_back (24); di.push_back (33); di.push_front (18); di.push_front (68); di.insert (di.begin () + 2, 47); print (di.begin (), di.end ()); // 68 18 47 24 33 di.pop_back (); di.pop_front (); di.erase (di.begin () + 1); print (di.begin (), di.end ()); // 18 24 di.push_back (20); sort (di.begin (), di.end ()); print (di.begin (), di.end ()); // 18 20 24 size_t size = di.size (); for (size_t i = 0; i < size; ++i) cout << di[i] << ' '; cout << endl; di.resize (10); print (di.begin (), di.end ()); return 0; }
fe.cpp
#include <iostream> //#include <algorithm> using namespace std; template<typename IT, typename DOIT> void for_each (IT begin, IT end, DOIT doit) { while (begin != end) doit (*begin++); } void print (int& x) { cout << x << endl; } void add (int& x) { ++x; } int main (void) { int a[5] = {1, 2, 3, 4, 5}; for_each (a, a + 5, print); for_each (a, a + 5, add); for_each (a, a + 5, print); return 0; }
insert.cpp
#include <algorithm> #include <vector> #include "print.h" template<typename iterator, typename type> iterator find (iterator begin, iterator end, const type& key) { for (; begin != end; ++begin) if (*begin == key) break; return begin; } bool cmpInt (const int& a, const int& b) { return a > b; } class CmpInt { public: CmpInt (bool less = true) : m_less (less) {} bool operator() (const int& a, const int& b) const{ return m_less ? (a < b) : (a > b); } private: bool m_less; }; int main (void) { int ai[] = {10, 20, 30, 40, 50}; vector<int> vi (ai, &ai[5]); print (vi.begin (), vi.end ()); vector<int>::iterator it = vi.begin (); it = vi.insert (it + 1, 15); print (vi.begin (), vi.end ()); ++++++it; it = vi.erase (it); print (vi.begin (), vi.end ()); cout << *it << endl; // 50 vi.insert (vi.begin (), 37); vi.insert (vi.begin () + 2, 43); vi.insert (vi.begin () + 4, 29); vi.push_back (18); vi.push_back (24); print (vi.begin (), vi.end ()); sort (vi.begin (), vi.end ()); print (vi.begin (), vi.end ()); sort (vi.begin (), vi.end (), /*cmpInt*/CmpInt (false)); print (vi.begin (), vi.end ()); it = ::find (vi.begin (), vi.end (), 18); if (it == vi.end ()) cout << "没找到!" << endl; else cout << "找到了:" << *it << endl; return 0; }
list.cpp
#include <list> #include "print.h" int main (void) { list<int> li; li.push_back (34); li.push_back (28); li.push_back (34); li.push_back (34); li.push_back (55); li.push_back (34); print (li.begin (), li.end ()); li.unique (); print (li.begin (), li.end ()); li.sort (); print (li.begin (), li.end ()); li.unique (); print (li.begin (), li.end ()); list<int> li2; li2.push_front (100); li2.push_front (200); li2.push_front (300); list<int>::iterator pos = li.begin (); ++pos; // li.splice (pos, li2); list<int>::iterator start = li2.begin (); ++start; // li.splice (pos, li2, start); list<int>::iterator end = li2.end (); li.splice (pos, li2, start, end); print (li.begin (), li.end ()); cout << li2.size () << endl; return 0; }
print.h
#ifndef _PRINT_H #define _PRINT_H #include <iostream> using namespace std; template<typename iterator> void print (iterator begin, iterator end) { while (begin != end) cout << *begin++ << ' '; cout << endl; } #endif // _PRINT_H
size.cpp
#include <iostream> #include <vector> using namespace std; void print (const vector<int>& vi) { cout << "大小:" << vi.size () << endl; cout << "容量:" << vi.capacity () << endl; for (vector<int>::const_iterator it = vi.begin (); it != vi.end (); ++it) cout << *it << ' '; cout << endl; } int main (void) { vector<int> vi (5, 3); print (vi); vi.push_back (4); print (vi); vi[6] = 100; cout << vi[6] << endl; vi.push_back (5); cout << vi[6] << endl; vi.resize (12); print (vi); vi.resize (2); print (vi); vi.clear (); print (vi); vi.reserve (20); print (vi); cout << vi[19] << endl; vi.reserve (5); print (vi); return 0; }
top.cpp
#include <iostream> #include <fstream> #include <vector> #include <algorithm> using namespace std; class Movie { public: friend istream& operator>> (istream& is, Movie& movie) { return is >> movie.m_title >> movie.m_comp >> movie.m_gross; } friend ostream& operator<< (ostream& os, const Movie& movie) { return os << movie.m_title << ' ' << movie.m_comp << ' ' << movie.m_gross; } bool operator< (const Movie& movie) const { return gross () > movie.gross (); } private: double gross (void) const { string str (m_gross); size_t pos = 0; while ((pos = str.find_first_of ("$,", pos)) != string::npos) str.erase (pos, 1); return atof (str.c_str ()); } string m_title; string m_comp; string m_gross; }; bool read (const char* file, vector<Movie>& vm) { ifstream ifs (file); if (! ifs) { perror ("打开票房文件失败"); return false; } Movie movie; while (ifs >> movie) vm.push_back (movie); ifs.close (); return true; } bool write (const char* file, const vector<Movie>& vm){ ofstream ofs (file); if (! ofs) { perror ("打开排行文件失败"); return false; } for (vector<Movie>::const_iterator it = vm.begin(); it != vm.end (); ++it) ofs << *it << endl; ofs.close (); return true; } int main (int argc, char* argv[]) { if (argc < 3) { cerr << "用法:" << argv[0] << " <票房文件> <排行文件>" << endl; return -1; } vector<Movie> vm; if (! read (argv[1], vm)) return -1; sort (vm.begin (), vm.end ()); if (vm.size () > 10) vm.resize (10); if (! write (argv[2], vm)) return -1; return 0; }
vector.cpp
#include <iostream> #include <vector> using namespace std; class A { public: A (int i = 0) : m_i (i) {}; int m_i; }; void print (const vector<int>& vi) { size_t size = vi.size (); cout << size << endl; for (size_t i = 0; i < size; ++i) cout << vi[i] << ' '; cout << endl; } int main (void) { vector<int> vi; vi.push_back (10); vi.push_back (20); vi.push_back (30); vi.push_back (20); vi.push_back (10); print (vi); vi.pop_back (); print (vi); ++vi.front (); vi.back () = 100; cout << vi.front () << ' ' << vi.back () << endl; typedef vector<int>::iterator IT; typedef vector<int>::const_iterator CIT; typedef vector<int>::reverse_iterator RIT; typedef vector<int>::const_reverse_iterator CRIT; for (IT it = vi.begin (); it != vi.end (); ++it) ++*it; const vector<int>& cvi = vi; for (CIT it = cvi.begin (); it != cvi.end (); ++it) cout << /*--*/*it << ' '; cout << endl; for (CRIT it = cvi.rbegin (); it!=cvi.rend(); ++it) cout << *it << ' '; cout << endl; vector<string> vs; vs.push_back ("beijing"); vs.push_back ("tianjin"); vs.push_back ("shanghai"); cout << *(vs.begin () + 2) << endl; *const_cast<char*> ((vs.end () - 1)->c_str ())='S'; cout << *(vs.end () - 1) << endl; vector<int> vi2 (10); print (vi2); vector<A> va (10); for (vector<A>::const_iterator it = va.begin (); it != va.end (); ++it) cout << it->m_i << ' '; cout << endl; vector<int> vi3 (10, 8); print (vi3); vector<A> va2 (10, A (8)); for (vector<A>::const_iterator it = va2.begin (); it != va2.end (); ++it) cout << it->m_i << ' '; cout << endl; return 0; }