抽象概念一定要被具象化才能被理解吗?

转载自 https://www.yueyao1982.com/phil_faq/faq_abstraction.html 若侵犯了内容创作者的权益,请联系删除 正文: 恰恰相反,具体的问题一定要抽象化之后才能理解,虽然这乍听起来比较奇怪。我们不妨想一想中学物理中最简单的问题,比如斜面上物体的运动。我们是先把物体和斜面都作了抽象化——物体和斜面都有很多细节,即“象”,而这些“象”被我们忽略了,或者说是抽离了,亦即“抽象”。所以,我们通过牛顿力学来理解机械运动,只是在理解抽象物体的相互关系,比如它们之间的作用,即力,比如它们之间的相对运动:简而言之,我们是在研究一个抽象模型,并试图理解这个模型。我们能做到最好的,就是我们的抽象化很合理,亦即被抽掉的“象”都是次要的;相应的,我们能得到最好的结果就是:模型的预测结果和实际的观测结果之间误差很小,一般来说不能没有误差,除非被观测值的可能性是离散甚至是有限的——比如电子的自旋只有两种可能。即使我们真的把主要因素抽掉,我们仍然可以理解那个被抽象出来的模型,只是那个模型和经验世界已经不能很好的对应了。 稍微深入一些来说,并非所有的抽象概念都能具象化,或者说概念的世界至少从规则和可能性这些方面来讲,并不受制于经验的世界,虽然没有经验概念就无从产生。比如我们观察过很多“经验中的马”,忽略了彼此不同的“象”,比如颜色、大小、公母等因素,就产生了“马的概念”;同样,我们观察过很多“经验世界中的鸟”,忽略了彼此不同的“象”,就产生了“鸟的概念”。“马的概念”和“鸟的概念”都可以被具象化到自然界中真实的动物。然而,我们的思维还可以对概念进行加工,比如我们对“鸟”概念进行切分,得到了“翅膀的概念”(当然它还是可以被具象化的)。然后我们把“翅膀的概念”和“马的概念”进行组合,得到了“天马”的概念——这个概念虽然可以具象化为具体的玩具或模型,但不再能具象化为自然界中的动物了。与此相似,我们还可以进行更复杂的概念建构,比如用更多的翅膀构建出“六翼天使”,比如用多种动物的不同部分构建出了“龙”和“麒麟”等神兽。当然,到此为止,这些概念至少还是可以被在一定程度上具象化,比如画成图画,比如做成雕刻。但是,更进一步的概念建构使这点也不可能了。如果我们把自然数的计数泛化到空间的维度上,我们就构建出了N维空间——1维空间、2维空间和3维空间是可以被具象化的,4维...

C标准模板库STL

 STL(Standard Template Library)简介

    STL是c++标准的一个组成部分,具有效率和易用性。

    STL的组成部分


容器是STL的核心,用来存储和组织数据。配置器是为容器服务的,复制其内存空间的分配和管理。迭代器是为算法服务的,算法通过迭代器访问容器中的数据。函数对象也是为算法服务的,通过配置不同的函数对象,可以改变算法的计算策略。适配器通过对已有的容器、迭代器和函数对象的改造,可以创造出新的编程组件。
    

示例代码
       
       这里添加代码
#include <cstdlib> 
#include <iostream> 
#include <vector> // 包含容器 vector 的头文件
#include <algorithm> // 包含算法头文件
using namespace std; // 使用名称空间 std 
template<class T
struct Print // 定义一个 Print 结构,作为函数对象来使用
{ 
    void operator()(T& x) const // 重载括号()运算符
    { 
        if( x % 2 == 0 ) // 如果参数是偶数
        { 
        cout<<x<<' '; // 输出参数
        }  
    } 
}; 
int main(int argc, char *argv[]) // 主函数
{ 
    cout<<"——使用 STL——"<<endl; 
    cout<<endl; 
    
    vector<int> vcInts; // 实例化一个 vector 容器
    for(int i = 0; i < 10; ++i) // 将整数 0 到 9 插入到容器中
        { 
        vcInts.push_back(i); 
        } 
    
    vector<int>::iterator iterBegin, iterEnd; // 定义两个迭代器
    iterBegin = vcInts.begin(); // 指向容器的开始
    iterEnd = vcInts.end(); // 指向容器的结尾
    cout<<"输出所有元素:"<<endl; 
    for(; iterBegin != iterEnd; ++iterBegin) // 用迭代器遍历整个容器
        { 
        cout << *iterBegin << " "; // 输出容器中的各个元素
        } 
    cout << endl; 
    
    cout<<"输出偶数元素:"<<endl; 
    iterBegin = vcInts.begin(); // 重新指向容器的开始
    for_each(iterBegin, iterEnd, Print<int>()); 
    // 通过算法 for_each 和函数对象 Print 输出容器中的元素
    
    cout<<endl<<endl; 
    return EXIT_SUCCESS; // 主函数返回
}

    由于代码重载了括号运算符(),所以可以当作一个函数对象使用。函数中定义了一个只存放int型数据的vector容器对象。程序最后调用for_each算法,并结合使用了函数对象print、for_each的行为类似于for循环。

    容器的分类

    容器(containers),顾名思义,就是用来装东西的。程序中的容器是指用来储存和组织数据的数据结构。为了支持泛型编程,这种数据结构应当写成模板类,所以在STL中所谓的容器就是各种类模板。
    
STL 容器基本上都支持容量的自动增长。添加数据时,如果容量不能满足要求, 容器就会自动分配新的内存,以用来容纳添加的数据。

 按照储存方式分类,容器可以分为序列式容器和关联式容器。所谓序列式容器,是指元素依照加入的顺序进行排序。所谓关联式容器,是指元素都是两部分组成的,分为键值(key)和实值(value)。键值和实值之间存在对应关系。当数据加入到容器中时,按照键值进行排序,因此关联式容器是自动有序的。

    


    序列式容器有两种存储方式。一种是连续存储,即容器中相邻元素的存储单元是连续的,新加入的元素总是放在最后一个元素的下一个存储单元中,数组就是这样一种连续存储的序列式容器。另外一种方式是链式存储,即相邻元素的存储单元不是连续的,而是用某种方式将其连接在一个,可以在元素中用一个(或多个)指针,指向相邻元素存储单元的地址,或者用整数表示相邻元素的存储索引。

    关联式容器也有两种存储方式。一种是使用搜索二叉树,容器中的元素依照其键值进行排序。另外一种是利用哈希表,容器中的元素按照其键值,根据哈希算法安置在不同的存储单元中。
    
    标准STL是用红黑树来实现关联式容器的。红黑树是一种查找效率更高的平衡搜索二叉树。

    容器的常用方法

    容器是用来存储数据的,因此容器一般具有如下方法:
    1.初始化(容器、初始值、元素的比较方法等)
    2.数据的增删查改。
    3.容器的数据统计(容器大小、元素数目)

初始化容器

    容器的初始化是在容器构造时完成的。初始化的内容包括容量、初始值、元素的比较方法等。一般来讲,序列式容器要求初始化容器,而关联式容器(基于红黑树的)要求初始化元素的比较方法。对于基于哈希表实现的关联式容器也要求初始化容量。
    



       
       这里添加代码
vector<int> vec( 12 ); // 构造整型向量,初始容量 12 
list<int> lst( 34 ); // 构造整型链表,初始容量 34 
struct ltstr // 重载了括号运算符的函数对象
{ 
 bool operator()(const char* s1, const char* s2) const 
 { 
 return strcmp(s1, s2) < 0; 
 } 
}; 
map<const char *, int > strIntMap( ltstr() ); 
 // 构造字符串到整型的映射,初始化键值比较方法为 ltstr 
set<const char *> strSet( ltstr() ); 
 // 构造字符串集合,初始化键值比较方法为 ltstr

两种类型的容器都可以在构造时设置初始值,初始值是用两个迭代器对象所标识的容器区间,新容器中的元素被初始化这个容器区间的值。

    

       
       这里添加代码
int ary1[5] = {1, 2, 3, 4, 5}; // 整型数组
vector<int> vec( ary1, ary1+5 ); // 用数组初始化向量
list<int> intList( vec.begin(), vec.end() ); // 用向量初始化链表
set<int> intSet( list.begin(), list.end() ); // 用链表初始化集合

    数组也是一种容器,由c++编译器预定义。vector和list的成员函数begin和end返回的是容器的迭代器,分别指示的容器的头和尾

此博客中的热门博文

算法的八大常用思想