C++速成笔记(十四) 向量 + 列表

本文详细介绍了C++中的迭代器概念,特别关注vector容器,包括其迭代器的使用方法、容量管理、元素存取以及向量的具体操作,如动态调整大小和元素的插入/删除。同时,还提及了列表(双向链表)的特性与操作。
摘要由CSDN通过智能技术生成

迭代器(iterator)是一种允许检查容器内元素,并实现元素遍历的 数据类型。迭代器提供了比下标操作更一般化的方法:所有的标准 库容器都定义了相应的迭代器类型,只有少数容器支持下标操作。 因为迭代器对所有的容器都适用,现代C++程序更倾向于使用迭代 器而不是下标操作访问容器元素。

向量vector是C++标准模板库中的内容。vector是一个容器,它能 够存放各种类型的对象,简单地说,vector是一个能够存放任意类 型的动态数组,可以动态改变大小。

函数原型:

//----迭代器iterators----
iterator begin(); //返回向量第1个元素为迭代器起始
iterator end(); //返回向量末尾元素为迭代器结束
reverse_iterator rbegin(); //返回向量末尾元素为逆向迭代器起始
reverse_iterator rend(); //返回向量第1个元素为逆向迭代器结束
//----容量capacity----
size_type size(); //返回向量元素数目
size_type max_size(); //返回向量能容纳的最大元素数目(长度)
void resize(size_type sz,T c=T()); //重置向量长度为sz,c填充到扩充元素中
size_type capacity(); //返回向量容器存储空间大小
bool empty(); //测试向量是否为空
void reserve(size_type n); //为向量申请能容纳n个元素的空间
//----元素存取element access----
operator[](size_type n); //返回向量第n个位置元素的运算符,n从0起
at(size_type n); //返回向量第n个位置元素,n从0起
front(); //返回向量第1个元素
back(); //返回向量末尾元素
//----向量调节器modifiers----
void assign(size_type n,const T& u); //向量赋n个u值
void push_back(const T& x); //增加一个元素到向量末尾
void pop_back(); //删除向量末尾元素
//在向量pos处插入n个元素值x,pos从1起
void insert(iterator pos,size_type n,const T& x);
iterator erase(iterator pos); //删除向量指定位置的元素,pos从1起
void swap(vector<T,Allocator>& vec); //与向量vec互换元素
void clear(); //清空向量 

示例:

#include <iostream>
#include <vector> //使用向量
using namespace std; //向量定义在std命名空间
int main()
{ //向量示例
    vector<int> V1, V2; //定义向量
    int A[]={1949,10,1} ,i;
    vector<int>::iterator It;
    V1.assign(A,A+3); //V1: 1949 10 1
    V2.assign(3,10); //V2: 10 10 10
    for (i=1; i<=5; i++) V1.push_back(i); //V1: 1949 10 1 1 2 3 4 5
    V1.pop_back(); //V1: 1949 10 1 1 2 3 4
    V1.front() -= V1.back(); //V1: 1945 10 1 1 2 3
    for(It=V1.begin(); It<V1.end(); It++) V2.push_back(*It);
    //遍历V1向量
    //V2: 10 10 10 1945 10 1 1 2 3 4
    V2.insert(V2.begin(),2,300);
    //V2: 300 300 10 10 10 1945 10 1 1 2 3 4
    V2.erase(V2.begin()+5);
    //V2: 300 300 10 10 10 10 1 1 2 3 4
    for(i=0;i<V2.size();i++) cout<<V2[i]<<" ";//输出V2向量元素
    return 0;
}

一、向量的具体操作

►向量(vector)类似数组,但向量是动态的,即它的元素个数可以 随时动态改变。例如:

vector<int> MyVec(100);//定义长度为100的向量
MyVec[50] = 1024;//给向量的某个元素赋值
int i =0 ;
for( ; i<25; i++ ){ MyVec.push_back(1);}
MyVec.resize(400);//重新定义向量的长度

自定义一个动态数组类模板。

#include <stdlib.h>
#include <iostream>
using namespace std;
enum ErrorType{ invalidArraySize,memoryAllocationError,indexOutOfRange };
char *errorMsg[]={"Invalid array size","Memory allocation error","Invalid index"};
template <class T>
class Array
{
    private:
        T *alist;
        int size;
        void Error(ErrorType error,int badIndex=0) const;
    public:
        Array(int sz=50); //构造函数
        Array(const Array<T>& A); //拷贝构造函数
        ~Array(void);//析构函数
        Array<T>& operator=(const Array<T>& rhs);
        T& operator[](int);
        operator T*() const;
        int ListSize() const;
        void Resize(int sz);
};

template <class T> //模板函数Error实现输出错误信息功能
void Array<T>::Error(ErrorType error,int badIndex) const
{
    cout<<errorMsg[error];//根据错误类型输出相应的错误信息
    if(error==indexOutOfRange) cout<<badIndex;
 //如果下标越界,输出错误的下标
    cout<<endl;
    exit(1);
}
template <class T>//构造函数
Array<T>::Array(int sz)
{
    if(sz<=0) //如果数组长度小于0则输出错误信息
        Error(invalidArraySize);
    else{//如果数组长度大于0则生成数组
        size=sz;
        alist=new T[size];//动态生成数组
        if(alist==NULL)//如果分配内存不成功则输出错误信息
            Error(memoryAllocationError);
    }
}
template <class T> //拷贝构造函数(深拷贝)
Array<T>::Array(const Array<T>& X)
{
    int n=X.size;
    size=n;
    alist=new T[n];
    if(alist==NULL)
        Error(memoryAllocationError);
    T *srcptr=X.alist; //X.alist是对象X的数组首地址
    T *destptr=alist; //本对象数组首地址
    while(n--) //逐个复制数组元素
        *destptr++=*srcptr++;
}

深拷贝,浅拷贝会导致两个指针指向同一个地址,在执行析构函数的时候,会析构一个迷途指针,会报错。

template <class T>//析构函数
Array<T>::~Array()
{ delete [] alist; }
template <class T>//重载“=”运算符,将一个数组赋值给另一个数组
Array<T>& Array<T>::operator =(const Array<T>& rhs)
{
    int n=rhs.size;
    if(size!=n)
    {
        delete [] alist;   //若 = 左右大小不同,则删去左边的元素,重新申请一样大的空间
        alist=new T[n];
        if(alist==NULL)
            Error(memoryAllocationError);
        size=n;
    }
    //从rhs向本对象复制元素
    T* destptr=alist;
    T* srcptr=rhs.alist;
    while(n--)    
        *destptr++=*srcptr++;
    return *this;//返回当前的对象
}
template <class T>//重载“[]”运算符,实现通过下标访问数组元素
T &Array<T>::operator [](int n)
{
    if(n<0||n>size-1) //检查下标是否越界
        Error(indexOutOfRange,n);
    return alist[n];//返回下标为n的数组元素
}
template <class T>//重载类型转换
Array<T>::operator T*() const
{
    return alist;
}
template <class T>//取当前数组的长度
int Array<T>::ListSize() const
{
return size;
}

重载类型转换,是为了之后创建指针指向该元素。

Array<int>a(10);
int *p=a;
template <class T>//修改数组的长度为sz
void Array<T>::Resize(int sz)
{
    if(sz<=0)
        Error(invalidArraySize);
    if(sz==size) return;
        T *newlist=new T[sz];
    if(newlist==NULL) Error(memoryAllocationError);
        int n=(sz<=size)?sz:size;//将sz和size中较小的一个赋给n
    T *srcptr=alist;//原数组的首地址
    T *destptr=newlist;//新数组的首地址
    while(n--)
        *destptr++=*srcptr++;
    delete [] alist;
    alist=newlist; size=sz;//使alist指向新数组,并更新sz
}
int main()
{
    int i,*p;
    Array<int> a(5);
    for(i=0;i<5;i++) cin>>a[i];
    for(i=0;i<5;i++) cout<<a[i]<<' '; cout<<endl;
    Array<int>b=a;
    for(i=0;i<5;i++) cout<<b[i]<<' '; cout<<endl;
    a.Resize(10);
    for(p=a;p<a+10;p++) cout<<*p<<' ';
    return 0;
}

二、列表

List是一个双向链表,因此它的内存空间是可以不连续的,通过指 针来进行数据的访问,这使得list的随机访问效率比较低,因此list 没有提供[]运算符的重载。但list可以很好的支持任意地方的插入和 删除操作,只需要移动指针即可

►列表类成员函数原型如下:

//----迭代器iterators----
iterator begin(); //返回表头元素为迭代器起始
iterator end(); //返回表尾元素为迭代器结束
reverse_iterator rbegin(); //返回表尾元素为逆向迭代器起始
reverse_iterator rend(); //返回表头元素为逆向迭代器结束
//----容量capacity----
bool empty(); //测试是否为空表
size_type size(); //返回列表长度
size_type max_size(); //返回列表能容纳的最大长度
void resize(size_type sz,T c=T()); //重置列表长度为sz,c填充到扩充元素中
//----元素存取element access----
front(); //返回表头元素
back(); //返回表尾元素
//----列表调节器modifiers----
void assign(size_type n,const T& u); //列表赋n个u值
void push_front(const T& x); //插入一个元素到表头
void pop_front(); //删除表头元素
void push_back(const T& x); //增加一个元素到表尾
void pop_back(); //删除表尾元素
//在列表pos处插入n个元素值x,pos从1起
void insert(iterator pos,size_type n,const T& x);
iterator erase(iterator pos); //删除列表指定位置的元素,pos从1起
void swap(list<T,Allocator>& lst); //与列表lst互换元素
void clear(); //清空列表
//----列表运算operations----
void remove(const T& value); //删除列表中值与value相同的所有元素
void remove_if(Predicate pred); //删除列表满足条件的元素
void unique(); //删除列表重复值
void merge(list<T,Allocator>& x); //合并列表x,列表必须有序
void sort(); //列表排序
void sort(Compare comp); //列表按comp关系比较排序
void reverse(); //列表逆序
#include <iostream>
#include <list> //使用列表
using namespace std; //列表定义在std命名空间
int main()
{
    int i, A[]={15,36,7,17};
    list<int>::iterator It;
    list<int> L1, L2, L3(A,A+4); //L3: 15 36 7 17
    for(i=1; i<=6;i++) L1.push_back(i); //L1: 1 2 3 4 5 6
    for(i=1; i<=3; i++) L2.push_back(i*10); //L2: 10 20 30
    It=L1.begin(); advance(It,2); //It指向3(第3个元素)
    L1.splice(It,L2); //L1: 1 2 10 20 30 3 4 5 6 L2(empty)
    //It仍然指向3(第6个元素)
    L2.splice(L2.begin(),L1,It);//L1:1 2 10 20 30 4 5 6 L2:3
    L1.remove(20); //L1: 1 2 10 30 4 5 6
    L1.sort(); //L1: 1 2 4 5 6 10 30
    L1.merge(L3); //L1: 1 2 4 5 6 10 15 30 36 7 17
    L1.push_front(L2.front()); //L1: 3 1 2 4 5 6 10 15 30 36 7 17
    L1.reverse(); //L1: 17 7 36 30 15 10 6 5 4 2 1 3
    for (It=L1.begin(); It!=L1.end(); ++It) cout<<*It<<" ";
    return 0;
}

三、列表的实现细节

list<char> MyList; //声明了list<char>模板类的一个实例
MyList.push_back(‘a’); //把一个对象放到一个list的后面
MyList.push_front (‘b’); //把一个对象放到一个list的前面
//用迭代器查找列表中值为‘c’的结点
list<char>::iterator FindIterator;
FindIterator=find(MyList.begin(),MyList.end(),
‘c’);
if(FindIterator==MyList.end()) cout<<“not find the char ‘c’!”;
else cout<<*FindIterator;

实现单向链表类模板:

#include <stdlib.h>
#include <iostream>
using namespace std;
template <class T>
class Node //结点类
{
    private:
        Node<T>*next;
    public:
        T data;
        Node(const T& item,Node<T>* ptrnext=NULL);
        void InsertAfter(Node<T> *p);
        Node<T> *DeleteAfter();
        Node<T> *NextNode() const;
};
template <class T>//构造函数
Node<T>::Node(const T& item,Node<T>* ptrnext):
     data(item),next(ptrnext){}

template <class T>//求下一个结点的地址
Node<T>*Node<T>::NextNode() const
{ return next; }

template <class T>//在当前结点之后插入一个结点p
void Node<T>::InsertAfter(Node<T>*p)
{
    p->next=next; //p结点指针域指向当前结点的后继结点
    next=p; //当前结点的指针域指向p结点
}
template <class T>//删除当前结点的后继结点,并返回其地址
Node<T> *Node<T>::DeleteAfter()
{
    Node<T> *tempPtr=next;//将欲删除的结点地址存储到tempPtr中
    if(next==NULL) return NULL;
 //如果当前结点没有后继结点则返回空
    next=tempPtr->next;//使当前结点的指针域指向tempPtr的后继结点
    return tempPtr;//返回被删除结点的地址
}
template <class T>//生成结点函数
Node<T> *GetNode(const T& item,Node<T> *nextPtr=NULL)
{
    Node<T> *newNode;
    newNode=new Node<T>(item,nextPtr);
    if(newNode==NULL)
    {
        cerr<<"Memory allocation failure!"<<endl;
        exit(1);
    }
    return newNode;
}
template <class T>//生成链表函数
Node<T> *CreateList(Node<T> *head,int n)
{
    Node<T> *currPtr,*newNode,data;
    currPtr=head=GetNode(0); //创建头结点
    for (; n>0; n--) { //创建n个结点链表
    cin>>data;
    newNode=GetNode(data);//创建新结点
    currPtr->next=newNode, currPtr=newNode;
    }
    currPtr->next=NULL; //尾结点
    return head;
}
enum AppendNewline{noNewline,addNewline}; //控制输出结点后是否换行
template <class T>//输出链表函数
void PrintList(Node<T> *head,AppendNewline addnl=noNewline)
{
    Node<T> *currPtr=head;
    while(currPtr!=NULL)
    {
    if(addnl==addNewline)
        cout<<currPtr->data<<endl;
    else
        cout<<currPtr->data<<" ";
    currPtr=currPtr->NextNode();
}
 
template <class T>//查找结点函数
int FindNode(Node<T> *head,T &item,Node<T> *prevPtr)
{
    Node<T> *currPtr=head;
    prevPtr=NULL;
    while(currPtr!=NULL)
    {
        if(currPtr->data=item) return 1;
        prevPtr=currPtr;
        currPtr=currPtr->NextNode();
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值