通过类模板实现顺序表时,若进行比较和遍历操作,模板元素可以通过STL中的equal_to仿函数实现,或者通过回调函数实现。若进行复制操作,可以采用STL的算法函数,也可以通过操作地址实现。关于回调函数和地址操作可以查看:C语言利用动态数组实现顺序表(不限数据类型)

  主要功能:初始化,按照索引插入,删除,遍历,按索引返回元素,返回顺序表的容量,元素个数,及扩容操作。

 #include <iostream>
#include <vector>
#include <string> using namespace std; //异常类
class illegalParameterValue{
public:
illegalParameterValue();
illegalParameterValue(string myMessage);
void outPutMessage();
private:
string message;
}; illegalParameterValue::illegalParameterValue(){
this->message = "illegal Parameter Value";
} illegalParameterValue::illegalParameterValue(string myMessage){
this->message = myMessage;
} void illegalParameterValue::outPutMessage(){
cout << this->message << endl;
} //自定义顺序表类模板
template<class T>
class arrayList{
public:
//构造函数
arrayList();
arrayList(int iniCapacity);
//复制构造函数
arrayList(const arrayList<T>& theList); ~arrayList(){ delete[] element; } //ADT方法
int mySize() const { return this->arrayListSize; }
int myCapacity() const { return this->arrayListCapacity; }
bool myEmpty() const { return arrayListSize == ; } void myForeach() const;
T& myGet(int index) const;
void myErasePos(int index);
void myEraseValue(T& theElement);
void myInsert(int index, T& theElement);
void output(ostream& out)const;
private:
int arrayListCapacity;
int arrayListSize;
T* element;
}; //构造函数,抛出异常时需要注意释放已创建的动态数据
//如果抛出异常后,没有处理,会继续向上抛出,直到main函数处理
//这里只是抛出,并没有捕获,因此不会显示message
template <class T>
arrayList<T>::arrayList(){} template <class T>
arrayList<T>::arrayList(int iniCapacity){
if (iniCapacity < )
{
string message = "the iniCapacity must be > 0";
throw illegalParameterValue(message);
}
//throw 1;
arrayListCapacity = iniCapacity;
element = new T[arrayListCapacity];
arrayListSize = ;
} template <class T>
arrayList<T>::arrayList(const arrayList<T>& theList){
arrayListCapacity = theList.arrayListCapacity;
arrayListSize = theList.arrayListSize;
element = new T[arrayListCapacity];
copy(theList.element, theList.element + arrayListSize, element);
} //ADT方法
//根据pos获取元素
template<class T>
T &arrayList<T>::myGet(int index)const{
if (index < || index >= arrayListSize){
throw illegalParameterValue("the index is wrong.");
}
return element[index];
} //按位置删除元素
template <class T>
void arrayList<T>::myErasePos(int index){
if (index < || index >= arrayListSize){
throw illegalParameterValue("the index is wrong.");
}
//整体移动
copy(element + index + , element + arrayListSize, element+ index );
arrayListSize--;
} //按值删除,仅删除第一次出现的位置,通过equal_to实现
template <class T>
void arrayList<T>::myEraseValue(T &theElement){ for (int i = ; i != arrayListSize; i++){
if (equal_to<T>()(element[i], theElement)){ cout << "mid" << endl;
myErasePos(i);
break;
}
}
} //按位置插入元素,并扩容
//这里有个非常隐蔽的错误,tmpElement通过new开辟内存空间
//按道理需要释放tmpElement,但tmpElement的地址赋给element,两个变量指向同一个内存地址
//element本身运行或下次进入条件就会析构掉,释放掉该块内存
//如果提前释放掉tmpElement,则提前释放了该块内存,则会二次释放造成内存泄漏
template <class T>
void arrayList<T>::myInsert(int index, T &theElement){
if (index < || index > arrayListSize){
throw illegalParameterValue("the index is wrong.");
} if (arrayListSize >= arrayListCapacity){
int tmpCapacity = arrayListCapacity * ;
T *tmpElement = new T[tmpCapacity];
copy(this->element, this->element+this->arrayListSize, tmpElement);
this->~arrayList();
this->element = tmpElement;
arrayListCapacity = arrayListCapacity * ;
//delete [] tmpElement;
}
copy_backward(this->element + index, this->element + arrayListSize, this->element + arrayListSize + );
this->element[index] = theElement;
arrayListSize++;
} //输出函数
template <class T>
void arrayList<T>::output(ostream& out)const{
copy(element, element + arrayListSize, ostream_iterator<T>(out, " "));
}
//重载<<
template <class T>
ostream& operator<<(ostream& out, const arrayList<T>& x){
x.output(out);
return out;
} int main(){
arrayList<int>mylist();
int a1 = , a2 = , a3 = ; mylist.myInsert(, a1);
mylist.myInsert(, a2);
mylist.myInsert(, a3); mylist.myErasePos();
int b = ;
mylist.myEraseValue(b);
mylist.output(cout);
cout << endl; cout << mylist.myGet() << endl;
mylist.output(cout); system("pause");
return ;
}

完整代码

自定义顺序表类

  通过类模板自定义顺序表类,并在类内实现了返回顺序表的容量和元素个数等操作。

 //自定义顺序表类模板
template<class T>
class arrayList{
public:
//构造函数
arrayList();
arrayList(int iniCapacity);
//复制构造函数
arrayList(const arrayList<T>& theList); ~arrayList(){ delete[] element; } //ADT方法
int mySize() const { return this->arrayListSize; }
int myCapacity() const { return this->arrayListCapacity; }
bool myEmpty() const { return arrayListSize == ; } void myForeach() const;
T& myGet(int index) const;
void myErasePos(int index);
void myEraseValue(T& theElement);
void myInsert(int index, T& theElement);
void output(ostream& out)const;
private:
int arrayListCapacity;
int arrayListSize;
T* element;
};

初始化

  利用C++类模板实现顺序表,最重要的是构造函数及复制构造函数。顺序表中的元素移动,通过STL的内置copy算法实现。另外,类外实现成员函数时,函数需要加作用域,成员属性可以直接使用,如element等。

 //构造函数,抛出异常时需要注意释放已创建的动态数据
//如果抛出异常后,没有处理,会继续向上抛出,直到main函数处理
//这里只是抛出,并没有捕获,因此不会显示message
template <class T>
arrayList<T>::arrayList(){} template <class T>
arrayList<T>::arrayList(int iniCapacity){
if (iniCapacity < )
{
string message = "the iniCapacity must be > 0";
throw illegalParameterValue(message);
}
//throw 1;
arrayListCapacity = iniCapacity;
element = new T[arrayListCapacity];
arrayListSize = ;
} template <class T>
arrayList<T>::arrayList(const arrayList<T>& theList){
arrayListCapacity = theList.arrayListCapacity;
arrayListSize = theList.arrayListSize;
element = new T[arrayListCapacity];
copy(theList.element, theList.element + arrayListSize, element);
}

索引元素

 //根据pos获取元素
template<class T>
T &arrayList<T>::myGet(int index)const{
if (index < || index >= arrayListSize){
throw illegalParameterValue("the index is wrong.");
}
return element[index];
}

索引插入

  索引插入时,需要对边界条件进行判断,由STL内置copy_backward算法实现顺序表元素的移动,因为需要将最右侧的元素先移动;copy算法是将最左侧的元素先移动。

  如果顺序表容量过小时,则需要对顺序表进行扩容,扩容需要注意两点:(1)需要将element指向新的空间;(2)利用临时变量动态扩容时,需要注意释放时机和释放对象。

 //按位置插入元素,并扩容
//这里有个非常隐蔽的错误,tmpElement通过new开辟内存空间
//按道理需要释放tmpElement,但tmpElement的地址赋给element,两个变量指向同一个内存地址
//element本身运行或下次进入条件就会析构掉,释放掉该块内存
//如果提前释放掉tmpElement,则提前释放了该块内存,则会二次释放造成内存泄漏
template <class T>
void arrayList<T>::myInsert(int index, T &theElement){
if (index < || index > arrayListSize){
throw illegalParameterValue("the index is wrong.");
} if (arrayListSize >= arrayListCapacity){
int tmpCapacity = arrayListCapacity * ;
T *tmpElement = new T[tmpCapacity];
copy(this->element, this->element+this->arrayListSize, tmpElement);
this->~arrayList();
this->element = tmpElement;
arrayListCapacity = arrayListCapacity * ;
//delete [] tmpElement;
}
copy_backward(this->element + index, this->element + arrayListSize, this->element + arrayListSize + );
this->element[index] = theElement;
arrayListSize++;
}

索引删除

   判断边界条件时需要注意,动态数组的索引与位置相差1,因此当index == arrayListsize时,也会报错。另外,需要注意删除后,元素个数减一。

 //按位置删除元素
template <class T>
void arrayList<T>::myErasePos(int index){
if (index < || index >= arrayListSize){
throw illegalParameterValue("the index is wrong.");
}
//整体移动
copy(element + index + , element + arrayListSize, element+ index );
arrayListSize--;
}

按值删除

   按值删除,这里仅实现了删除元素第一次出现的位置,顺序表中元素间的比较通过STL关系运算符仿函数实现。另外,该函数不具有普适性,对int, float等大部分内置类型可以适用,对于结构体等数据类型,需要对函数进行重载,改变函数参数。如,age和name的class,仿函数不能直接对对象进行比较,只能是对某一个成员属性进行比较。C语言中是用回调函数,让用户自定义操作。

 //按值删除,仅删除第一次出现的位置,通过equal_to实现
template <class T>
void arrayList<T>::myEraseValue(T &theElement){ for (int i = ; i != arrayListSize; i++){
if (equal_to<T>()(element[i], theElement)){ cout << "mid" << endl;
myErasePos(i);
break;
}
}
}

遍历

  对于类模板实现遍历操作, 需要用到STL中的输出流迭代器,另外需要对<<进行重载。C语言中是用回调函数进行操作的,需要用户根据数据类型自定义输出函数。

 //输出函数
template <class T>
void arrayList<T>::output(ostream& out)const{
copy(element, element + arrayListSize, ostream_iterator<T>(out, " "));
}
//重载<<
template <class T>
ostream& operator<<(ostream& out, const arrayList<T>& x){
x.output(out);
return out;
}

C++利用动态数组实现顺序表(不限数据类型)的更多相关文章

  1. C语言利用动态数组实现顺序表(不限数据类型)

    实现任意数据类型的顺序表的初始化,插入,删除(按值删除:按位置删除),销毁功能.. 顺序表结构体 实现顺序表结构体的三个要素:(1)数组首地址:(2)数组的大小:(3)当前数组元素的个数. //顺序表 ...

  2. "《算法导论》之‘线性表’":基于动态分配的数组的顺序表

    我们利用静态分配的数组来实现的顺序表的局限还是挺大的,主要在于它的容量是预先定好的,用户不能根据自己的需要来改变.如果为了后续用户能够自己调整顺序表的大小,动态地分配数组空间还是很有必要的.基于动态分 ...

  3. "《算法导论》之‘线性表’":基于静态分配的数组的顺序表

    首先,我们来搞明白几个概念吧(参考自网站数据结构及百度百科). 线性表 线性表是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外, ...

  4. 使用JAVA数组实现顺序表

    1,引入了JAVA泛型类,因此定义了一个Object[] 类型的数组,从而可以保存各种不同类型的对象. 2,默认构造方法创建了一个默认大小为16的Object数组:带参数的构造方法创建一个指定长度的O ...

  5. HDU 2819 ——Swap——————【最大匹配、利用linker数组、邻接表方式】

     Swap Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status ...

  6. Java实现顺序表

    利用顺序存储结构表示的顺序表称为顺序表. 它用一组连续的地址存储单元一次存放线性表中的数据元素. 顺序表的实现是数据结构中最简单的一种. 由于代码中已经有详细注释,代码外不再阐述. 下次再陈上关于顺序 ...

  7. 数据结构 单链表&顺序表

    顺序表: 一般使用数组(C语言中的数组采用顺序存储方式.即连续地址存储)来描述. 优点:在于随机访问元素, 缺点:插入和和删除的时候,需要移动大量的元素. 链表: 优点:插入或删除元素时很方便,使用灵 ...

  8. 数据结构4:顺序表(线性表的顺序存储结构)及C语言实现

    逻辑结构上呈线性分布的数据元素在实际的物理存储结构中也同样相互之间紧挨着,这种存储结构称为线性表的顺序存储结构. 也就是说,逻辑上具有线性关系的数据按照前后的次序全部存储在一整块连续的内存空间中,之间 ...

  9. c语言进阶12-线性表之顺序表

    一.  线性表的定义 为什么要学习线性表呢? 因为我们日常生活中存在种数据关系,计算机程序是为了解决日常生活的数据关系,因此我们要学习线性表. 线性表是什么呢? 线性表是由n个元素组成的有限序列. 需 ...

随机推荐

  1. NFS 服务器的配置

    1. 安装 NFS 服务器 [root@localhost btools]#rpm -q nfs-utils 如果没有安装,从对应 Linux 操作系统版本的安装光盘上找到 nfs-utils 的安装 ...

  2. API Gateway和Route 53及CloudFront的连携使用

    API Gateway部署出来之后的url网址对于普通用户并不友好,所以肯定是需要一个正常的域名来作为url进行访问. 主要有以下几点, API Gateway可以自定义域名 自定义的域名要从Rout ...

  3. CyberArk

    CyberArk PIM 套件由5个部分组成: · CyberArk EPV (Enterprise Password Vault)– 企业密码保险库 基于CyberArk 专利的Vault技术,为企 ...

  4. 基本TCP Sockets编程

    一.socket 函数 #include <sys/socket.h> int socket (int family, int type, int protocol); Returns: ...

  5. 多台服务器-SSH免密登录设置

    在4台服务器-SSH免密登录设置,如以下4台服务器 master1 node001 node002 node003 我想在master1对4台服务器进行拉取或者分发任务或者是集群服务器的批量操作,但是 ...

  6. (转载)openwrt nginx

    ln -s ../../../feeds/packages/net/fcgiwrap/ fcgiwrap 本帖最后由 cjd6568358 于 2018-6-4 11:21 编辑 刚又把路由器重置重新 ...

  7. HAProxy服务器 、Keepalived热备 、Keepalived+LVS

    配置HAProxy负载平衡集群 1.1 问题 准备三台Linux服务器,两台做Web服务器,一台安装HAProxy,实现如下功能: 客户端访问HAProxy,HAProxy分发请求到后端Real Se ...

  8. IDEA maven package失败

    选中要打包的模块,选择工具栏中的Build,选择Rebuild Module xxx,重新打包

  9. NX二次开发-UFUN创建圆锥UF_MODL_create_cone1

    NX11+VS2013 #include <uf.h> #include <uf_modl.h> UF_initialize(); //创建圆锥 UF_FEATURE_SIGN ...

  10. c#种GetType()和TypeOf()的区别

    C#中任何对象都具有GetType()方法,它的作用和typeof()相同,返回Type类型的当前对象的类型. typeof(x)中的x,必须是具体的类名.类型名称等,不可以是变量名称:GetType ...