6.5-数据结构&算法-标准模板STL/STL容器/向量

Posted xuxaut-558

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

 
 
 

以上是关于6.5-数据结构&算法-标准模板STL/STL容器/向量的主要内容,如果未能解决你的问题,请参考以下文章

标准模板库

6.4-数据结构&算法-模板/函数模板/类模板/特化

模板+测试工作文档模板+1测试策略&测试计划

CPP strings 与标准模板库

基本算置顶各大算法&&数据结构模板

link-1-STL 标准模板库