STL相关

  一、容器  
作为STL的最主要组成部分--容器,分为向量(vector),双端队列(deque),表(list),队列(queue),堆栈(stack),集合(set),多重集合(multiset),映射(map),多重映射(multimap)。

容器

特性

所在头文件

向量vector

可以用常数时间访问和修改任意元素,在序列尾部进行插入和删除时,具有常数时间复杂度,对任意项的插入和删除就有的时间复杂度与到末尾的距离成正比,尤其对向量头的添加和删除的代价是惊人的高的

<vector>

双端队列deque

基本上与向量相同,唯一的不同是,其在序列头部插入和删除操作也具有常量时间复杂度

<deque>

表list

对任意元素的访问与对两端的距离成正比,但对某个位置上插入和删除一个项的花费为常数时间。

<list>

队列queue

插入只可以在尾部进行,删除、检索和修改只允许从头部进行。按照先进先出的原则。

<queue>

堆栈stack

堆栈是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项。即按照后进先出的原则

<stack>

集合set

由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列,没有两个不同的元素能够拥有相同的次序,具有快速查找的功能。但是它是以牺牲插入车删除操作的效率为代价的

<set>

多重集合multiset

和集合基本相同,但可以支持重复元素具有快速查找能力

<set>

映射map

由{键,值}对组成的集合,以某种作用于键对上的谓词排列。具有快速查找能力

<map>

多重集合multimap

比起映射,一个键可以对应多了值。具有快速查找能力

<map>

考虑到不同的实际需要,更主要的是效率的需要,我们可以选择不同的容器来实现我们的程序,以此达到我们提高性能的目的。

二、算法
算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。<algorithm>是所有STL头文件中最大的一个,它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。<functional>中则定义了一些模板类,用以声明函数对象。

STL的算法也是非常优秀的,它们大部分都是类属的,基本上都用到了C++的模板来实现,这样,很多相似的函数就不用自己写了,只要用函数模板就OK了。

我们使用算法的时候,要针对不同的容器,比如:对集合的查找,最好不要用通用函数find(),它对集合使用的时候,性能非常的差,最好用集合自带的find()函数,它针对了集合进行了优化,性能非常的高。

三、迭代器

 

迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器不仅仅是指针,因此你不能认为他们一定具有地址值。例如,一个数组索引,也可以认为是一种迭代器。

迭代器有各种不同的创建方法。程序可能把迭代器作为一个变量创建。一个STL容器类可能为了使用一个特定类型的数据而创建一个迭代器。作为指针,必须能够使用*操作符类获取数据。你还可以使用其他数学操作符如++。典型的,++操作符用来递增迭代器,以访问容器中的下一个对象。如果迭代器到达了容器中的最后一个元素的后面,则迭代器变成past-the-end值。使用一个past-the-end值得指针来访问对象是非法的,就好像使用NULL或为初始化的指针一样。

提示

STL不保证可以从另一个迭代器来抵达一个迭代器。例如,当对一个集合中的对象排序时,如果你在不同的结构中指定了两个迭代器,第二个迭代器无法从第一个迭代器抵达,此时程序注定要失败。这是STL灵活性的一个代价。STL不保证检测毫无道理的错误。


它的具体实现在<itertator> 中,我们完全可以不管迭代器类是怎么实现的,大多数的时候,把它理解为指针是没有问题的(指针是迭代器的一个特例,它也属于迭代器),但是,决不能完全这么做。

迭代器功能(Abilities Of Iterator Gategories)
输入迭代器
Input iterator
向前读
Reads forward
istream
输出迭代器
Output iterator
向前写
Writes forward
ostream,inserter
前向迭代器
Forward iterator
向前读写
Read and Writes forward
 
双向迭代器
Bidirectional iterator
向前向后读写
Read and Writes forward and
backward
list,set,multiset,map,mul
timap
随机迭代器
Random access iterator
随机读写
Read and Write with random
access
vector,deque,array,string

由此可见,指针和迭代器还是有很大差别的。和指针最接近的就是随机访问迭代器

#include"stdafx.h"
#include <iostream.h>
#include <algorithm>
 
using namespace std;
 
#define SIZE 100
int iarray[SIZE];
 
int main()
{
  iarray[20] = 50;
  int* ip = find(iarray, iarray + SIZE, 50);
   if (ip != NULL) 
	   // 当使用STL函数时,只能测试ip是否和past-the-end 值是否相等。尽管在本例中ip是一个C++指针,其用法也必须符合STL迭代器的规则。
  if (ip == iarray + SIZE)                  
	  // 为了判断find()是否成功,例子中测试ip和 past-the-end 值是否相等: 
    cout << "50 not found in array" << endl;  
      //如果表达式为真,则表示在搜索的范围内没有指定的值。否则就是指向一个合法对象的指针
  else
    cout << *ip << " found in array" << endl; //
  return 0;
}


 

尽管C++指针也是迭代器,但用的更多的是容器迭代器。容器迭代器用法和iterdemo.cpp一样,但和将迭代器申明为指针变量不同的是,你可以使用容器类方法来获取迭代器对象。两个典型的容器类方法是begin()和end()。它们在大多数容器中表示整个容器范围。其他一些容器还使用rbegin()和rend()方法提供反向迭代器,以按反向顺序指定对象范围。

下面的程序创建了一个矢量容器(STL的和数组等价的对象),并使用迭代器在其中搜索。该程序和前面的程序相同。

#include"stdafx.h"
#include <iostream.h>
#include <algorithm>
#include <vector>
 
using namespace std;
 
vector<int> intVector(100);
 
void main()
{
  intVector[20] = 50;
  vector<int>::iterator intIter =
    find(intVector.begin(), intVector.end(), 50);
  if (intIter != intVector.end())
    cout << "Vector contains value " << *intIter << endl;
  else
    cout << "Vector does not contain 50" << endl;
}

输入迭代器
 

#include"stdafx.h"
#include"stdafx.h"
#include <iostream.h>
#include <algorithm>
#include <vector>
 
using namespace std;
 
vector<int> intVector(100); 

//输入迭代器是最普通的类型。输入迭代器至少能够使用==和!=测试是否相等;使用*来访问数据;使用++操作来递推迭代器到下一个元素或到达past-the-end 值。
//修改一下测试 呵呵
template <class InputIterator, class T>
InputIterator find2(InputIterator first, InputIterator last, const T& value) {
    while (first != last && *first != value) ++first;
    return first;
  }
void main()
{
  intVector[20] = 5;
  vector<int>::iterator intIter; //和指针一样,你可以给一个迭代器赋值。例如,首先申明一个迭代器
  intIter=find2(intVector.begin(), intVector.end(), 50);
  if (intIter != intVector.end())
    cout << "Vector contains value " << *intIter << endl;
  else
    cout << "Vector does not contain 50" << endl;
  getchar();
}

输出迭代器

当使用copy()算法的时候,你必须确保目标容器有足够大的空间,或者容器本身是自动扩展的

#include"stdafx.h"
#include <iostream.h>
#include <algorithm>   // Need copy()
#include <vector>      // Need vector
 
using namespace std;
 
double darray[10] =
  {1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9};
 
vector<double> vdouble(10);
 
int main()
{
  vector<double>::iterator outputIterator = vdouble.begin();
  copy(darray, darray + 10, outputIterator);
  while (outputIterator != vdouble.end()) {
    cout << *outputIterator << endl;
    outputIterator++;
  }
  return 0;
}

前推迭代器

template <class ForwardIterator, class T>
void replace (ForwardIterator first,
              ForwardIterator last,
              const T& old_value,
              const T& new_value);
replace(vdouble.begin(), vdouble.end(), 1.5, 3.14159);

双向迭代器

/*双向迭代器要求能够增减。如reverse()算法要求两个双向迭代器作为参数:
*/
template <class BidirectionalIterator>
void reverse (BidirectionalIterator first,
              BidirectionalIterator last);
//使用reverse()函数来对容器进行逆向排序:

reverse(vdouble.begin(), vdouble.end());


 

随机访问迭代器

/*随机访问迭代器能够以任意顺序访问数据,并能用于读写数据(不是const的C++指针也是随机访问迭代器)。STL的排序和搜索函数使用随机访问迭代器。随机访问迭代器可以使用关系操作符作比较。
*/
//random_shuffle() 函数随机打乱原先的顺序。申明为:

template <class RandomAccessIterator>
void random_shuffle (RandomAccessIterator first,
                     RandomAccessIterator last);
//使用方法:

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

对于迭代器,有另一种方法使用流和标准函数。理解的要点是将输入/输出流作为容器看待。因此,任何接受迭代器参数的算法都可以和流一起工作。

#include"stdafx.h"
#include <iostream>
#include <stdlib.h> // Need random(), srandom()
#include <time.h> // Need time()
#include <algorithm> // Need sort(), copy()
#include <vector> // Need vector
#include <iterator>

using namespace std;

void Display(vector<int>& v, const char* s);

int main()
{
    // Seed the random number generator
    srand ( time(NULL) );

    // Construct vector and fill with random integer values
    vector<int> collection(10);
    for (int i = 0; i < 10; i++)
        collection[i] = rand() % 10000;;

    // Display, sort, and redisplay
    Display(collection, "Before sorting");
    sort(collection.begin(), collection.end());
    Display(collection, "After sorting");
    return 0;
}

// Display label s and contents of integer vector v
void Display(vector<int>& v, const char* s)
{
    cout << endl << s << endl;
    copy(v.begin(), v.end(),
        ostream_iterator<int>(cout, "\t"));
    cout << endl;
}


插入迭代器

插入迭代器用于将值插入到容器中。它们也叫做适配器,因为它们将容器适配或转化为一个迭代器,并用于copy()这样的算法中。例如,一个程序定义了一个链表和一个矢量容器:

list<double> dList;
vector<double> dVector;

通过使用front_inserter迭代器对象,可以只用单个copy()语句就完成将矢量中的对象插入到链表前端的操作:

copy(dVector.begin(), dVector.end(), front_inserter(dList));

三种插入迭代器如下:

·        普通插入器 将对象插入到容器任何对象的前面。

·        Front inserters 将对象插入到数据集的前面——例如,链表表头。

·        Back inserters 将对象插入到集合的尾部——例如,矢量的尾部,导致矢量容器扩展。

使用插入迭代器可能导致容器中的其他对象移动位置,因而使得现存的迭代器非法。例如,将一个对象插入到矢量容器将导致其他值移动位置以腾出空间。一般来说,插入到象链表这样的结构中更为有效,因为它们不会导致其他对象移动。


#include"stdafx.h"
#include <iostream>
#include <algorithm>
#include <list>
#include <iterator>

using namespace std;

int iArray[5] = { 1, 2, 3, 4, 5 };

void Display(list<int>& v, const char* s);

int main()
{
    list<int> iList;

    // Copy iArray backwards into iList
    copy(iArray, iArray + 5, front_inserter(iList));
    Display(iList, "Before find and copy");

    // Locate value 3 in iList
    list<int>::iterator p =
        find(iList.begin(), iList.end(), 3);

    // Copy first two iArray values to iList ahead of p
    copy(iArray, iArray + 2, inserter(iList, p));
    Display(iList, "After find and copy");

    return 0;
}

void Display(list<int>& a, const char* s)
{
    cout << s << endl;
    copy(a.begin(), a.end(),
        ostream_iterator<int>(cout, " "));
    cout << endl;
}



 

//功能是分别对数组,向量,表,多重集合进行插入操作,对每个容器插入100万个随机整数;

#include"stdafx.h"
#include<iostream>
#include<iterator>
#include<vector>
#include<list>
#include<set>
#include<time.h>
#include<conio.h>
#include<algorithm>
using namespace std;
template<typename T>
void arrayInsert(T*a,T*s,long size)     //向数组插入数据
{
    //for(long i=0;i<10;i++)   // //好像数组支持不到100万,我们就算10万的
                                          //最后在把把结果乘以10吧,
    //{
        for(long k=0;k<size;k++)
        {
            a[k]=s[k];  
        }
    //}
}
template<typename T>
void vectorInsert( vector<T> *v,T*s,long size)      //向向量插入数据
{
    for(int i=0;i<10;i++)
    {
        for(long k=0;k<size;k++)
        {
            v->push_back(s[k]); 
       }
    }
}
template<typename T>
void listInsert(list<T>*l,T*s,long size)    //向表插入数据
{
    for(int i=0;i<10;i++)
    {
        for(long k=0;k<size;k++)
        {
            l->push_back(s[k]);
        }   
    }
}
template<class
T>
void multisetInsert(multiset<T>*s1,T*s,long size)    //向多重集合插入数据
{
    for(int i=0;i<10;i++)
    {
        for(long k=0;k<size;k++)
        {
            s1->insert(s[k]);   
        }
    }
}
int* genIntData(long size)                   //生成随机数
{
    int* data=new int[size];
    generate(&data[0],&data[size],rand);
    return data;
}   
int main(void)
{
    const long size=100000;
    int* s_data,array1[size];
    double begin,end;
    s_data=genIntData(size);
   vector<int> vector1;
    list<int> list1;
    multiset<int> multiset1;
    clock();
    cout<<"?"<<endl;
    begin=(double)clock()/CLK_TCK;
    arrayInsert<int>(array1,s_data,size);
    end=(double)clock()/CLK_TCK;
    cout<<"??"<<(end-begin)<<endl;
    getch();
    begin=(double)clock()/CLK_TCK;
    vectorInsert<int>(&vector1,s_data,size);
    end=(double)clock()/CLK_TCK;
    cout<<"??"<<(end-begin)<<endl;
    getch();
    begin=(double)clock()/CLK_TCK;
    listInsert<int>(&list1,s_data,size);
    end=(double)clock()/CLK_TCK;
    cout<<"??"<<(end-begin)<<endl;
    getch();
    begin=(double)clock()/CLK_TCK;
    multisetInsert<int>(&multiset1,s_data,size);
    end=(double)clock()/CLK_TCK;
    cout<<"??"<<(end-begin)<<endl;
    getch();
    free(s_data);
    return 0;       
}


 



   

你可能感兴趣的:(Algorithm,算法,vector,iterator,Random,sorting)