Essential C++学习笔记及源代码(第3章 泛型编程风格)

第3章介绍了C++语言中使用标准模板库(STL)进行泛型编程的方式

导言:Standard Template Library(STL)主要由2种组件构成:一是容器包括vector、list、set、map等class;另一种组件是用以操作这些容器的泛型算法,包括find()、sort()、replace()、merge()等。

1、vector和list是顺序性容器。在顺序性容器上可以进行和常规数组一样的迭代方式。set和map属于关联性容器。关联性容器可以快速地查找容器中的元素值。

2、map是一对对的key/balue组合。key用于查找,value用来表示我们要储存或取出的数据。举例来说,电话号码可以用map表示。用户名是key,value则是电话号码。

3、set与map相比,其中只含有key。我们对它进行查询操作为的是判断值是否存在于其中。如果我们想要建立一组索引表,用来记录出现于新闻、故事中的字眼,我们可能会将一些中性字眼如the、an、but排除掉。在让某个字眼进入索引表之前,先查询excluded_word这么一个set,如果这个字眼在里面,便忽略它;反之则加入索引表。

4、泛型算法提供了许多可用于容器及数组上的操作。这些算法之所以被称为泛型(generic),是因为它们和它们想要操作的元素类型无关。举个例子,它们和元素类型究竟是int、double或string没有关系。同样和容器class彼此独立(不论是vector、list还是数组)。

本章作者使用了一系列find算法来逐步模拟标准库中的find泛型算法进而教导读者们如何实现泛型算法,并且使用了标准库中的函数对象less、plus等取代函数指针从而更加使得算法泛型化,在最后使用了iterator从输入输出流中读取数据,不依赖于cin和cout等。

原书中的程序中有部分错误,经笔者修改后可通过C++11及更高标准运行,读者可与原书附带的程序进行对照。

附上笔者所写的课后练习答案。

//ch3_main.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <functional>
#include <algorithm>
using namespace std;
const int int_size = 12;
const int string_size = 4;
const int int_not_present = 1024;

static int ia[int_size] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144};
static string sa[string_size] = {"pooh", "piglet", "eeyore", "tigger"};

static vector<int> ivec(ia, ia + int_size);
static vector<string> svec(sa, sa + string_size);

//第1个find函数, 查找vector<int>中的元素;
const int *find_ver1(const vector<int> &vec, int value)
{
    for (int ix = 0; ix < vec.size(); ++ix)
    {
        if (vec[ix] == value)
        {
            return &vec[ix];
        }
    }
    return nullptr;
}

//第2个find函数, 查找vector中自定义类型的元素;
template <typename elemType>
const elemType *find_ver2(const vector<elemType> &vec, const elemType &value)
{
    for (int ix = 0; ix < vec.size(); ++ix)
    {
        if (vec[ix] == value)
        {
            return &vec[ix];
        }
    }
    return nullptr;
}

//mybegin函数防止获取错误的起始位置;
template <typename elemType>
inline const elemType *mybegin(const vector<elemType> &vec) //源程序begin与标准库中的函数重名需改为mybegin;
{
    return vec.empty() ? nullptr : &vec[0];
}

//myend函数防止获取错误的终止位置;
template <typename elemType>
inline const elemType *myend(const vector<elemType> &vec) //源程序end与标准库中的函数重名需改为myend;
{
    return vec.empty() ? nullptr : &vec[vec.size()];
}

//第3个find函数, 传入数组长度查找数组中自定义类型的元素(使用下标);
template <typename elemType>
const elemType *find_ver3(const elemType *array, int size, const elemType &value)
{
    if (array == nullptr || size < 1)
    {
        return nullptr;
    }
    for (int ix = 0; ix < size; ++ix)
    {
        if (array[ix] == value) //下标法;
        {
            return &array[ix];
        }
    }
    return nullptr;
}

//第4个find函数, 传入数组长度查找数组中自定义类型的元素(使用指针);
template <typename elemType>
const elemType *find_ver4(const elemType *array, int size, const elemType &value)
{
    if (array == nullptr || size < 1)
    {
        return nullptr;
    }
    for (int ix = 0; ix < size; ++ix, ++array)
    {
        if (*array == value) //指针法;
        {
            return array;
        }
    }
    return nullptr;
}

//第5个find函数, 使用数组首地址和末地址查找数组中自定义类型的元素;
template <typename elemType>
const elemType *find_ver5(const elemType *first, const elemType *last, const elemType &value)
{
    if (first == nullptr || last == nullptr)
    {
        return nullptr;
    }
    while (first != last)
    {
        if (*first == value)
        {
            return first;
        }
        ++first;
    }
    return nullptr;
}

//第6个find函数, 查找可迭代类型的容器中的元素;
template <typename IteratorType, typename elemType>
IteratorType find_ver6(IteratorType first, IteratorType last, const elemType &value)
{
    while (first != last)
    {
        if (value == *first)
        {
            return first;
        }
        ++first;
    }
    return last;
}

//测试上述的所有find函数;
void prog_find_vers()
{
    const int *iptr = find_ver1(ivec, ivec[2]); //使用vector<int>测试find1函数;
    if (iptr != &ivec[2])
    {
        cerr << "?? find_ver1 failed!\n";
    }
    else
    {
        cerr << "!! find_ver1 ok!\n";
    }

    const string *sptr = find_ver2(svec, svec[2]); //使用vector<string>测试find2函数;
    if (sptr != &svec[2])
    {
        cerr << "?? find_ver2 failed with string!\n";
    }
    else
    {
        cerr << "!! find_ver2 ok with string!\n";
    }

    iptr = find_ver2(ivec, ivec[2]); //使用vector<int>测试find2函数;
    if (iptr != &ivec[2])
    {
        cerr << "?? find_ver2 failed with int!\n";
    }
    else
    {
        cerr << "!! find_ver2 ok with int!\n";
    }

    iptr = find_ver3(ia, int_size, ia[2]); //使用int数组测试find3函数;
    if (iptr != &ia[2])
    {
        cerr << "?? find_ver3 failed with int array!\n";
    }
    else
    {
        cerr << "!! find_ver3 ok with int array!\n";
    }

    sptr = find_ver3(sa, string_size, sa[2]); //使用string数组测试find3函数;
    if (sptr != &sa[2])
    {
        cerr << "?? find_ver3 failed with string array!\n";
    }
    else
    {
        cerr << "!! find_ver3 ok with string array!\n";
    }

    iptr = find_ver4(mybegin(ivec), ivec.size(), ivec[2]); //使用vector<int>和mybegin函数测试find4函数;
    if (iptr != &ivec[2])
    {
        cerr << "?? find_ver4 failed with int vector!\n";
    }
    else
    {
        cerr << "!! find_ver4 ok with int vector!\n";
    }

    sptr = find_ver4(mybegin(svec), svec.size(), svec[2]); //使用vector<string>和mybegin函数测试find4函数;
    if (sptr != &svec[2])
    {
        cerr << "?? find_ver4 failed with string vector!\n";
    }
    else
    {
        cerr << "!! find_ver4 ok with string vector!\n";
    }

    sptr = find_ver5(sa, sa + string_size, sa[2]); //使用string数组测试find5函数;
    if (sptr != &sa[2])
    {
        cerr << "?? find_ver5 failed with string array!\n";
    }
    else
    {
        cerr << "!! find_ver5 ok with string array!\n";
    }

    iptr = find_ver5(mybegin(ivec), myend(ivec), ivec[2]); //使用vector<int>和边界判断函数测试find5函数;
    if (iptr != &ivec[2])
    {
        cerr << "?? find_ver5 failed with int vector!\n";
    }
    else
    {
        cerr << "!! find_ver5 ok with int vector!\n";
    }

    iptr = find_ver5(mybegin(ivec), myend(ivec), int_not_present); //使用vector<int>和边界元素测试find5函数;
    if (iptr != 0)
    {
        cerr << "?? find_ver5 failed with int not present in vector!\n";
    }
    else
    {
        cerr << "!! find_ver5 ok with int not present in vector!\n";
    }

    sptr = find_ver6(sa, sa + string_size, sa[2]); //使用string数组测试find6函数;
    if (sptr != &sa[2])
    {
        cerr << "?? find_ver6 failed with string array and iterators!\n";
    }
    else
    {
        cerr << "!! find_ver3 ok with string array and iterators!\n";
    }

    vector<int>::iterator it = find_ver6(ivec.begin(), ivec.end(), ivec[2]); //使用vector<int>测试find6函数;
    if (*it != ivec[2])
    {
        cerr << "?? find_ver6 failed with int vector and iterators!\n";
    }
    else
    {
        cerr << "!! find_ver4 ok with int vector and iterators!\n";
    }
    return;
}

vector<int> less_than_10(const vector<int> &vec)
{
    vector<int> nvec;
    for (int ix = 0; ix < vec.size(); ++ix)
    {
        if (vec[ix] < 10)
        {
            nvec.push_back(vec[ix]);
        }
    }
    return nvec;
}

bool less_than(int v1, int v2)
{
    return v1 < v2;
}

bool greater_than(int v1, int v2)
{
    return v1 > v2;
}

//函数指针pred提高元素compare适用性;
vector<int> filter_ver1(const vector<int> &vec, int filter_value, bool (*pred)(int, int))
{
    vector<int> nvec;

    for (int ix = 0; ix < vec.size(); ++ix)
    {
        if (pred(vec[ix], filter_value))
        {
            nvec.push_back(vec[ix]);
        }
    }
    return nvec;
}

//使用标准库中的less<int>和bind2nd进行元素比较;
vector<int> filter_ver2(const vector<int> &vec, int val, less<int> lt)
{
    vector<int> nvec;
    vector<int>::const_iterator iter = vec.begin();

    while ((iter = find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end())
    {
        nvec.push_back(*iter);
        iter++;
    }
    return nvec;
}

//使用输入iterator和输出iterator完善filter函数;
template <typename InputIterator, typename OutputIterator,
          typename ElemType, typename Comp>
OutputIterator
filter_ver3(InputIterator first, InputIterator last,
            OutputIterator at, const ElemType &val, Comp pred)
{
    while ((first = find_if(first, last, bind2nd(pred, val))) != last)
    {
        *at++ = *first++;
    }
    return at;
}

vector<int> sub_vec(const vector<int> &vec, int val)
{
    vector<int> local_vec(vec);
    sort(local_vec.begin(), local_vec.end()); //元素升序排序;

    //找到第一个大于val的元素;
    vector<int>::iterator iter = find_if(local_vec.begin(), local_vec.end(), bind2nd(greater<int>(), val));
    local_vec.erase(iter, local_vec.end()); //删除之后的所有比val大的元素;
    return local_vec;
}

//测试上述的所有filter函数;
void prog_filter_vers()
{
    const int solution_size = 6;

    vector<int> local_vec = less_than_10(ivec); //返回一个所有元素小于10的vector<int>;
    if (local_vec.size() != solution_size)
    {
        cerr << "?? less_than_10 failed! expected expected ";
        cerr << solution_size << ", received: ";
        cerr << local_vec.size() << endl;
    }
    else
    {
        cerr << "!! less_than_10 ok!\n";
    }

    const int partition_value = 10;
    local_vec = filter_ver1(ivec, partition_value, greater_than); //使用greater_than函数处理并返回一个所有元素大于10的vector<int>;
    if (local_vec.size() != solution_size)
    {
        cerr << "?? filter_ver1 failed! expected expected ";
        cerr << solution_size << ", received: ";
        cerr << local_vec.size() << endl;
    }
    else
    {
        cerr << "!! filter_ver1 ok!\n";
    }

    local_vec = filter_ver2(ivec, partition_value, less<int>()); //使用less模板处理并返回一个所有元素大于10的vector<int>;
    if (local_vec.size() != solution_size)
    {
        cerr << "?? filter_ver2 failed! expected ";
        cerr << solution_size << ", received: ";
        cerr << local_vec.size() << endl;
    }
    else
    {
        cerr << "!! filter_ver2 ok!\n";
    }

    int ia2[solution_size];
    filter_ver3(ia, ia + int_size, ia2, partition_value, less<int>()); //使用纯模板函数filter_ver3处理元素并放置在数组ia2中;

    int err_cnt = 0;
    for (int ix = 0; ix < solution_size; ++ix)
    {
        if (ia[ix] != ia2[ix])
        {
            ++err_cnt;
        }
    }
    if (err_cnt)
    {
        cerr << "?? filter_ver3 failed for array! ";
        cerr << err_cnt << " unexpected values\n";
    }
    else
    {
        cerr << "!! filter_ver3 for array ok!\n";
    }

    vector<int> ivec2(solution_size);
    filter_ver3(ivec.begin(), ivec.end(), ivec2.begin(), partition_value, greater<int>());
    //使用纯模板函数filter_ver3处理元素并放置在定长vector中;
    err_cnt = 0;
    int ix = solution_size;
    for (int iy = 0; ix < ivec.size(); ++ix, ++iy)
    {
        if (ivec[ix] != ivec2[iy])
        {
            ++err_cnt;
        }
    }
    if (err_cnt)
    {
        cerr << "?? filter_ver3 failed for vector! ";
        cerr << err_cnt << " unexpected values\n";
    }
    else
    {
        cerr << "!! filter_ver3 for vector ok!\n";
    }

    vector<int> ivec3;
    filter_ver3(ivec.begin(), ivec.end(), back_inserter(ivec3), partition_value, greater<int>());
    //使用纯模板函数filter_ver3处理元素并使用back_inserter逐渐添加至ivec3的末尾;
    if (ivec3.size() != solution_size)
    {
        cerr << "?? filter_ver3 with back inserter failed! expected ";
        cerr << solution_size << ", received: ";
        cerr << ivec3.size() << endl;
    }
    else
    {
        cerr << "!! filter_ver3 with back inserter ok!\n";
    }
    ivec3 = sub_vec(ivec, partition_value); //删除ivec中所有大于partition_value的元素并赋值给ivec3;
    if (ivec3.size() != solution_size)
    {
        cerr << "?? sub_vec failed! expected ";
        cerr << solution_size << ", received: ";
        cerr << ivec3.size() << endl;
    }
    else
    {
        cerr << "!! sub_vec ok!\n";
    }
    return;
}

//从stdin流输入数据并输出至stdout流中;
void prog_io_std()
{
    cout << "Please enter some text, then indicate end of file!\n";

    istream_iterator<string> is(cin);
    istream_iterator<string> eof;
    vector<string> text;

    copy(is, eof, back_inserter(text));
    sort(text.begin(), text.end());
    ostream_iterator<string> os(cout, " ");
    copy(text.begin(), text.end(), os);
    return;
}

//文件输入输出;
void prog_io_fil()
{
    ifstream in_file("input_file.txt");
    //使用前应创建一个文本文件input_file.txt处理输入;
    ofstream out_file("output_file.txt");
    //使用前应创建一个文本文件output_file.txt处理输出;

    if (!in_file || !out_file)
    {
        cerr << "?? unable to open the necessary files.\n";
        return;
    }
    else
    {
        cerr << "!! ok: input and output files opened!\n";
    }
    istream_iterator<string> is(in_file);
    istream_iterator<string> eof;
    vector<string> text;

    copy(is, eof, back_inserter(text));
    if (text.empty())
    {
        cerr << "?? iostream iterators failed: string vector empty!\n";
    }
    else
    {
        cerr << "!! iostream iterators seem to work: ";
        cerr << text.size() << " strings read in!\n";
    }
    sort(text.begin(), text.end());
    ostream_iterator<string> os(out_file, " ");
    unique_copy(text.begin(), text.end(), os);
    return;
}

void prog_io_iters()
{
    //prog_io_std();
    //↑测试标准流中的输入输出, 若是想测试可以处理掉注释;
    prog_io_fil();
}

int main()
{
    cerr << "About to execute prog_find_vers()\n";
    prog_find_vers();

    cerr << "\n\nAbout to execute prog_filter_vers()\n";
    prog_filter_vers();

    cerr << "\n\nAbout to execute prog_io_iters()\n";
    prog_io_iters();

    cerr << "\n\nOk -- done!\n";
    return 0;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise3.1.cpp

#include <iostream>
#include <fstream>
#include <set>
#include <map>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;

const string one[6] = {"a", "an", "or", "the", "and", "but"};

int main()
{
    string tmp;
    ifstream in_file("input_file.txt");
    ofstream out_file("output_file.txt");
    set<string> excluded_words;
    map<string, int> words;

    if (!in_file || !out_file)
    {
        cerr << "Can't open the necessary files." << endl;
        return -1;
    }
    excluded_words.insert(one, one + 6); //把单字添加至set集合中;
    while (in_file >> tmp)
    {
        if (excluded_words.find(tmp) == excluded_words.end())
        {
            ++words[tmp];
        }
    }
    char ch;
    cout << "Would you like to search a key in this input_file.txt? (y/n) ";
    cin >> ch;
    if (ch == 'y' || ch == 'Y')
    {
        cout << "Please enter a word to search (q to quit): ";
        while (cin >> tmp, tmp != "q")
        {
            int times = words.count(tmp);
            cout << tmp << (times == 0 ? " doesn't " : " ");
            cout << "exist in the input_file." << endl;
            if (times != 0)
            {
                cout << tmp << " occurs " << times << " times." << endl;
            }
            cout << "Can you search again? (q to quit): ";
        }
    }
    else
    {
        cout << "Thank you for the question." << endl;
    }
    map<string, int>::iterator it;
    for (it = words.begin(); it != words.end(); ++it)
    {
        cout << it->first << ": " << it->second << endl;
    }

    return 0;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise3.2.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;

class LessThan
{
public:
    bool operator()(const string &s1, const string &s2)
    {
        return s1.size() < s2.size();
    }
};

int main()
{
    vector<string> text;
    ifstream in_file("input_file.txt");
    istream_iterator<string> is(in_file);
    istream_iterator<string> eof;
    ostream_iterator<string> os(cout, " ");

    if (!in_file)
    {
        cerr << "Can't open the file input_file.txt." << endl;
        return -1;
    }
    copy(is, eof, back_inserter(text));
    sort(text.begin(), text.end(), LessThan());
    cout << "Sorted:\n";
    copy(text.begin(), text.end(), os);

    return 0;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise3.3.cpp

#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
const int size = 6;

const string fa[size] = {"lippman", "smith", "mailer", "franz", "orlen", "ranier"};
const vector<string> a[size] = {{"danny", "anna"}, {"john", "henry", "frieda"}, {"tommy", "june"}, {}, {"orley"}, {"alphonse", "lou", "robert", "brodie"}};

void init(map<string, vector<string>> &f);
void query(map<string, vector<string>> &f);
void show(map<string, vector<string>> &f);

int main()
{
    map<string, vector<string>> families;

    init(families);
    query(families);
    show(families);

    return 0;
}

void init(map<string, vector<string>> &f)
{
    for (int i = 0; i < size; ++i)
    {
        f[fa[i]] = a[i];
    }
    return;
}

void query(map<string, vector<string>> &f)
{
    string family;

    cout << "Please enter a family name to search or q to quit: ";
    while (cin >> family, family != "q")
    {
        map<string, vector<string>>::const_iterator it = f.find(family);
        if (it == f.end())
        {
            cout << "Sorry. The ";
            cout << family << " family is not currently entered.\n";
        }
        else
        {
            cout << "The " << family << " family ";
            if (0 == it->second.size())
            {
                cout << "has no children\n";
            }
            else
            {
                cout << "has " << it->second.size() << " children: ";
                for (auto x = it->second.begin(); x != it->second.end(); ++x)
                {
                    cout << *x << ' ';
                }
                cout << endl;
            }
        }
        cout << "You can enter a name to search again or q to quit: ";
    }
    return;
}

void show(map<string, vector<string>> &f)
{
    for (auto x : f)
    {
        cout << "The " << x.first << " family ";
        if (x.second.empty())
        {
            cout << "has no children.\n";
        }
        else
        {
            cout << "has " << x.second.size() << " children: ";
            for (auto it = x.second.begin(); it != x.second.end(); ++it)
            {
                cout << *it << ' ';
            }
            cout << endl;
        }
    }
    return;
}

//-----------------------------------------------------------;

//-----------------------------------------------------------;
//Practise3.4.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;

class even_elem
{
public:
    bool operator()(int elem)
    {
        return elem % 2 != 0;
    }
};

int main()
{
    vector<int> input;
    istream_iterator<int> in(cin);
    istream_iterator<int> eof;
    ofstream odd_file("odd_file.txt");
    ofstream even_file("even_file.txt");

    if (!even_file || !odd_file)
    {
        cerr << "Can't open the necessary files.";
        return -1;
    }
    copy(in, eof, back_inserter(input));
    //使用STL方法stable_partition分割奇数和偶数;
    vector<int>::iterator division = stable_partition(input.begin(), input.end(), even_elem());
    ostream_iterator<int> odd_iter(odd_file, " ");
    ostream_iterator<int> even_iter(even_file, "\n");
    copy(input.begin(), division, even_iter);
    copy(division, input.end(), odd_iter);
    cout << "Done.\n";

    return 0;
}

//-----------------------------------------------------------;

//--------------------------------------------2021年7月6日 ----------------------------------------------------

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MZZDX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值