vector

       STL提供了一组表示容器、迭代器、函数对象和算法的模板。容器是一个与数组类似的单元,可以存储若干个值。STL容器是同质的,即存储的值的类型相同;算法是完成特定任务的厨房,迭代器能够用来遍历容器的对象,与能够遍历数组的指针类似,是广义指针;函数对象是类似于函数的对象,可以是类对象或函数指针。

       STL不是面向对象的编程,而是一种不同的编程模式——泛型编程(generic programming)。

       创建vector模板对象,使用通常的<type>表示法来指出要使用的类型。另外,vector模板使用动态内存分配,因此可以用初始化参数来指出需要多少矢量。

//vect1.cpp -- introducing the vector template
#include <iostream>
#include <string>
#include <vector>

const int NUM=5;
using namespace std;

int main()
{
    using std::vector;
    using std::string;
    using std::cin;
    using std::cout;
    vector<int> ratings(NUM);
    vector<string> titles(NUM);
    cout<<"You will do exactly as told. You will enter\n"
        <<NUM<<" book titles and your ratings (0-10).\n";
    int i;
    for(i=0;i<NUM;i++)
    {
        cout<<"Enter title #"<<i+1<<": ";
        getline(cin,titles[i]);
        cout<<"Enter your rating (0-10): ";
        cin>>ratings[i];
        cin.get();
    }
    cout<<"Thank you. You entered the following:\n"
        <<"Rating\t Book\n";
    for(i=0;i<NUM;i++)
    {
        cout<<ratings[i]<<"\t"<<titles[i]<<endl;
    }
    return 0;
}
introducing the vector template

      所有的STL容器都提供了一些基本方法,其中包括size()——返回容器中元素数目、swap()——交换两个容器的内容、begin()——返回一个指向容器中第一个元素的迭代器、end()——返回一个表示超过容器尾的迭代器。

       迭代器:广义指针。它是指针,也是可对其执行类似指针的操作的对象。通过将指针广义化为迭代器,让STL能够为各种不同的容器类提供统一的接口。迭代器是一个名为iterator的typedef,其作用域为整个类。

vector<double>::iterator pd;
vector<double> scores;
pd=scores.begin();
*pd++;
++pd;
vector<double>::iterator pd=scores.begin();
auto pd=scores.begin();
example1

        迭代器的行为就像指针,还有上面例子中的C++11自动类型推断很有用。

        超尾:迭代器指向容器最后一个元素后面的那个元素。这与C-风格字符串最后一个字符后面的空字符类似,只是空字符是一个值,而“超过结尾“是一个指向元素的指针(迭代器)。end()成员函数标识超过结尾的位置。push_back()是一个方便的方法,它将元素添加到矢量末尾。这样做时,它将负责内存管理,增加矢量的长度,是指能够容纳新的成员。因此在编写或运行程序时,无需了解元素的数目。只要能够取得足够的内存,程序就可以根据需要增加长度。

  erase()方法删除矢量中给定区间的元素。它接受两个迭代器参数,这些参数定义了要删除的区间。了解STL如何使用两个迭代器来定义区间至关重要。第一个迭代器指向区间的起始处,第二个迭代器位于区间终止处的后一个位置。例如,下述代码删除第一个和第二个元素,即删除begin()和begin()+1指向的元素。

scores.erase(scores.begin(),scores.begin()+2);

  如果it1和it2是迭代器,则STL文档使用[p1,p2)来表示(不包括p2)的区间。

  insert()方法的功能与erase()相反。它接受3个迭代器参数,第一个参数指定了新元素的插入位置,第二个和第三个地带其参数定义了被插入区间,该区间通常是另一个容器对象的一部分。例如,下面的代码将矢量new_v中除第一个元素外的所有元素插入到old_v矢量的第一个元素前面:

vector<int> old_v;
vector<int> new_v;
old_v.insert(old_v.begin(),new_v.begin()+1,new_v.end());
//vect2.cpp -- methods and iterators
#include <iostream>
#include <string>
#include <vector>

struct Review{
    std::string title;
    int rating;
};
bool FillReview(Review & rr);
void ShowReview(const Review &rr);

int main()
{
    using std::cout;
    using std::vector;
    vector<Review> books;
    Review temp;
    while(FillReview(temp))
        books.push_back(temp);
    int num=books.size();
    cout<<num<<std::endl;
    if(num>0)
    {
        cout<<"Thank you. You entered the following:\n"
            <<"Rating\tBook\n";
        for(int i=0;i<num;i++)
            ShowReview(books[i]);//数组下标输出
        cout<<"Reprising:\n"
            <<"Rating\tBook\n";
        vector<Review>::iterator pr;
        for(pr=books.begin();pr!=books.end();pr++)
            ShowReview(*pr);//迭代器输出
        vector<Review> oldlist(books);//复制
        if(num>3)
        {
            books.erase(books.begin()+1,books.begin()+3);//删除第二个和第三个
            cout<<"After erasure:\n";
            for(pr=books.begin();pr!=books.end();pr++)
                ShowReview(*pr);
            books.insert(pr=books.begin(),oldlist.begin()+1,oldlist.begin()+2);//元素插入books第一个元素的前面,将oldllist中第二个元素插入。
            cout<<"After insertion:\n";
            for(pr=books.begin();pr!=books.end();pr++)
                ShowReview(*pr);
        }
        books.swap(oldlist);//交换两个容器的内容
        cout<<"Swapping oldlist with books:\n";
        for(pr=books.begin();pr!=books.end();pr++)
            ShowReview(*pr);
    }
    else
        cout<<"Nothing entered, nothing gained.\n";
    return 0;
}

bool FillReview(Review & rr)
{
    std::cout<<"Enter book title (quit to quit): ";
    std::getline(std::cin,rr.title);
    if(rr.title=="quit")
        return false;
    std::cout<<"Enter book rating: ";
    std::cin>>rr.rating;
    if(!std::cin)
        return false;
    while(std::cin.get()!='\n')
        continue;
    return true;
}

void ShowReview(const Review & rr)
{
    std::cout<<rr.rating<<"\t"<<rr.title<<std::endl;
}
methods and iterators

  STL从更广泛的角度定义了非成员(non-member)函数来执行这些操作,即不是为每个容器定义find()成员函数,而是定义了一个适用于所有容器类的非成员函数find()。STL有时也会定义一个成员函数。这是因为对有些操作来说,类特定算法的效率比通用算法高,因此,vector的成员函数swap()的效率比非成员函数swap()高,但非成员函数让您能够交换两个类型不同的容器的内容。

  下面来看3个具有代表性的STL函数:for_each()、random_shuffle()和sort()。for_each()函数可用于很多容器类,它接受3个参数。前两个是定义容器中区间的迭代器,最后一个是指向函数的指针。for_each()函数将被指向的函数用于容器区间中的各个元素。被指向的函数不能修改容器元素的值可以用for_each()函数来代替for循环。

for_each(books.begin(),books.end(),ShowReview);
这样可避免显式地使用迭代器变量。

  循环和关系表达式中说过,基于范围的for循环是为用于STL而设计的。

double prices[5]={1,2,3,4,5};
for(double x:prices)    
    cout<<x<<std::endl;

  在这种for循环中,括号内的代码声明一个类型与容器存储的内容相同的变量,然后指出了容器的名称。接下来,循环体使用指定的变量依次访问容器的每个元素。

for_each(books.begin(),books.end(),ShowReview);

  可将其替换为下述给予范围的for循环:

for(auto x:books) ShowReview(x);

  根据book的类型(vector<Review>),编译器将推断出x的类型为Review,而循环将依次将books中的每个Review对象传递给ShowReview()。

  不同于for_each(),基于范围的for循环可修改容器的内容,诀窍是指定一个引用参数。

void InflateReview(Review &r){    r.rating++;    }
for(auto &x:books) InflateReview(x);

  Random_shuffle()函数接受两个指定区间的迭代器参数,并随机排列该区间中的元素。

random_shuffle(books.begin(),books.end());

  与可用于任何容器类的for_each不同,该函数要求容器类允许随机访问,vector可以做到这一点。

  sort()函数也要求容器支持随机访问。该函数有两个版本,第一个版本接受两个定义区间的迭代器参数,并使用为存储在容器中的支持类型元素定义的<运算符,对区间中的元素进行操作。如果容器元素是用户自定义的对象,则要使用sort(),必须定义能够处理该类型对象的operator<()函数。

注:与operator<相比,WorseThan()函数执行的对Review对象进行排序的工作不那么完整,如果两个对象的title相同,operator<()函数将按rating进行排序,而WorseThan()将他们视为完全相同。第一种视为全排序 (total ordering),第二种排序称为完整弱排序(strict weak ordering)。全排序顺序必然相同,完整弱排序中等价不相同。

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

struct Review{
    std::string title;
    int rating;
};

bool operator<(const Review &r1, const Review &r2);
bool worseThan(const Review &r1, const Review &r2);
bool FillReview(Review & rr);
void ShowReview(const Review &rr);
void InflateReview(Review & r)
{
    r.rating++;
}
int main()
{
    using namespace std;

    vector<Review> books;
    Review temp;
    while(FillReview(temp))
        books.push_back(temp);
    if(books.size()>0)
    {
        cout<<"Thank you. You entered the following "
            << books.size()<<" ratings:\n"
            <<"Rating\tBook\n";
        for_each(books.begin(),books.end(),ShowReview);

        sort(books.begin(), books.end());
        cout<<"Sorted by title:\nRating\tBook\n";
        for_each(books.begin(),books.end(),ShowReview);

        sort(books.begin(),books.end(),worseThan);
        cout<<"Sorted by rating:\nRating\tBook\n";
        for_each(books.begin(),books.end(),ShowReview);

        random_shuffle(books.begin(),books.end());
        cout<<"After shuffling:\nRating\tBook\n";
        for_each(books.begin(),books.end(),ShowReview);

        for (auto &x : books) InflateReview(x);
        cout<<"After InflateReview:\nRating\tBook\n";
        for (auto x:books) ShowReview(x);
    }
    else
        cout<<"No entries. ";
    cout<<"Bye.\n";
    return 0;
}

bool operator<(const Review & r1, const Review & r2)
{
    if(r1.title<r2.title)
        return true;
    else if(r1.title==r2.title&&r1.rating<r2.rating)
        return true;
    else
        return false;
}

bool worseThan(const Review & r1, const Review & r2)
{
    if(r1.rating<r2.rating)
        return true;
    else
        return false;
}

bool FillReview(Review & rr)
{
    std::cout<<"Enter book title (quit to quit): ";
    std::getline(std::cin,rr.title);
    if(rr.title=="quit")
        return false;
    std::cout<<"Enter book rating: ";
    std::cin>>rr.rating;
    if(!std::cin)
        return false;
    while(std::cin.get()!='\n')
        continue;
    return true;
}

void ShowReview(const Review & rr)
{
    std::cout<<rr.rating<<"\t"<<rr.title<<std::endl;
}
using STL functions

 

posted @ 2018-08-21 17:00  子诚-  阅读(247)  评论(0编辑  收藏  举报