算法与C++

c++ STL 重剑无锋

2019-02-01  本文已影响11人  Vophan

在现在,总是有人鼓吹c++是一门不好的语言,说他比c慢,说他发展变了味道,说他语法歧义,但是没有一个人可以说他不强大。

这里引用轮子哥在知乎的一个回答:

STL作为一个模范放在那里人们都不看,
非要去写披着C++外衣的C语言
披着C++外衣的java
中枪踩坑学不会都是正常的。这根本不是C和C++哪个好的问题,是大众对C++的误解造成的。在用C++的时候,自己水平不高,就不要去用C的部分。都是因为人类的意志力太脆弱,才造成这么多问题的。


之前,我感觉不到c++ 强大在哪里?今天我接触到c++的STL的通用容器与通用算法后,我感觉c++ 不在是那个c with class。

通用算法

注:下面内容为我从Thinking In Cpp学习到的东西以及自己写的代码

copy

为什么对这个函数这么有感觉?是因为一直以来,我都觉得c/c++的数组赋值方式令人不舒服,不可以按值传递,简直了。
所以当看到这个函数时,眼前一亮。

示例:

//
// Created by vophan on 19-2-1.
//

#include <algorithm>
#include <cassert>
#include <cstddef>

int main() {
    int a[] = {1,2,3,4,5};
    const size_t SIZE = sizeof a / sizeof a[0];
    int b[SIZE];
    std::copy(a, a+SIZE, b);
    for (size_t i = 0; i < SIZE; ++i) {
        assert(a[i] == b[i]);
    }
}

然后,在这里注意一下,最后的for循环,我们如果不想看到他呢?

//
// Created by vophan on 19-2-1.
//

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <iostream>

int main() {
    int a[] = {1,2,3,4,5};
    const size_t SIZE = sizeof a / sizeof a[0];
    int b[SIZE];
    std::copy(a, a+SIZE, std::ostream_iterator<int>(std::cout, "\n"));
//    std::copy(a, a+SIZE, b);
//    for (size_t i = 0; i < SIZE; ++i) {
//        assert(a[i] == b[i]);
//    }
}

什么是ostream_iterator?
先卖个关子。

equal

我们前面检验数组是否复制成功,用了断言和循环,现在我们换一个方式:

//
// Created by vophan on 19-2-1.
//

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <iostream>

int main() {
    int a[] = {1,2,3,4,5};
    const size_t SIZE = sizeof a / sizeof a[0];
    int b[SIZE];
    std::copy(a, a+SIZE, b);
    assert(std::equal(a, a+SIZE, b));
}

当然,如果equal只能比较两个整数数组,那确实没什么意思,但是实际上他可以处理任何一种类型。但是你需要重载==运算符。

struct student {
    float grade;
    std::string name;
    float height;
    student(float grade, std::string name, float height) {
        this->grade = grade;
        this->name = name;
        this->height = height;
    }
    bool operator==(student &s) const;
};

bool student::operator==(student &s) const {
    if (grade == s.grade and height == s.height and name == s.name) {
        return true;
    } else {
        return false;
    }
}

但是要注意:

如果要把一个序列(sequence)拷贝到一个容器(container)中去,通常用std::copy算法,代码如下:
std::copy(start, end, std::back_inserter(container));

back_inserter

这个东西是什么呢?对比两段代码大家就知道了。

#include <cassert>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstddef>

using namespace std;

int main() {
    int a[] = {1,2,3,4,5};
    const size_t SIZE = sizeof a / sizeof a[0];
    vector<int> v1(a, a + SIZE);
    vector<int> v2(SIZE);
    copy(v1.begin(), v1.end(), v2.begin());
    assert(equal(v1.begin(), v1.end(), v2.begin()));
}
#include <cassert>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstddef>

using namespace std;

int main() {
    int a[] = {1,2,3,4,5};
    const size_t SIZE = sizeof a / sizeof a[0];
    vector<int> v1(a, a + SIZE);
//    vector<int> v2(SIZE);
    vector<int> v2;
    copy(v1.begin(), v1.end(), back_inserter(v2));
    assert(equal(v1.begin(), v1.end(), v2.begin()));
}

没错,back_inserter为我们省去了初始化vector的过程,实际上,back_inserter是将原来的“为后面的元素赋值”变为了“将元素插入到后面”。

replace_copy_if && remove_copy_if && replace_if

我理解这几个函数其实就是:选择型复制,复制符合某种条件的值,尽管这在python里算是基操,但是在c++里用模板编程实现还是蛮麻烦的,而且我认为:这应该也是c++中回调机制的体现,将调用者与制造者分离,互不干涉。

#include <algorithm>
#include <iostream>
#include <cstddef>

using namespace std;

bool gt15 (int x) {return x > 15;}

int main() {
    int a[] = {10, 20, 30};
    const size_t size = sizeof a / sizeof a[0];
    int b[size];
    int *endb = remove_copy_if(a, a+size, b, gt15);
    int *begb = b;
    while (begb != endb) {
        cout<<*begb++<<endl;
    }
    return 0;
}

注意:执行结果是10,说明是remove了符合条件的值,所以很符合这个名字

#include <algorithm>
#include <iostream>
#include <cstddef>

using namespace std;

bool containE(string s) {return s.find("e") != string::npos;}

int main() {
    string a[] = {
            "read",
            "my",
            "lips"
    };
    const size_t size = sizeof a / sizeof a[0];
    string b[size];
    string *endb = replace_copy_if(a, a+size, b, containE, "kiss");
    string *begb = b;
    while (begb != endb) {
        cout<<*begb++<<endl;
    }
}

同理,自行理解replace
而replace_if 则是改变自己的序列,而不是复制。

c++
上一篇 下一篇

猜你喜欢

热点阅读