通过类模板实现顺序表时,若进行比较和遍历操作,模板元素可以通过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. mongodb入门篇

    MongoDB 入门篇 分类: NoSQL, 故障解决 undefined 1.1 数据库管理系统 在了解MongoDB之前需要先了解先数据库管理系统 1.1.1 什么是数据? 数据(英语:data) ...

  2. docker Dockerfile学习---构建apache环境

    1.创建目录,上传包 创建项目目录 $ mkdir apache_php $ cd apache_php 把包下载后放到服务器该目录下 $ ls apr-....tar.gz 2.创建Dockerfi ...

  3. c++11 std::move()

    简单点理解,c++11 中的std::move() 函数,实际上就是将一个左值强制转换成一个右值引用数据类型,从而可以调用相应的对右值引用重载的函数. 如果使用std::move() 的返回值做为参数 ...

  4. mysql 的linux 忘记了密码

    1.首先确认服务器出于安全的状态,也就是没有人能够任意地连接MySQL数据库. 因为在重新设置MySQL的root密码的期间,MySQL数据库完全出于没有密码保护的 状态下,其他的用户也可以任意地登录 ...

  5. Oracle使用——PLSQL的中文乱码显示全是问号--Oracle查询中文乱码

      问题 这两天刚将PLSQL与Oracle配置好,可是在PLSQL中插入数据时,出现一个问题,PLSQL中的表里无法显示中文,中文无法保存.无法输出,中文在表中显示问号,如图: 原因 经过一番查证, ...

  6. thymeleaf种处理select,radio和文字回显的问题

    select根据后台集合显示下列列表 <select class="form-control" name="parentId" > <opti ...

  7. PHP 实现斐波那契数列

    使用循环实现 <?php $arr[1] = 1; for($i = 2;$i < 100;$i++) { $arr[$i] = $arr[$i-1] + $arr[$i-2]; } ec ...

  8. [HL] 7.5 集训总结

    对于某唤做赛区难度的题,我只能是内流满面..拿到题,A神题不可做,B,神题不可做,C,神题不可做...最后yy了一个A的算法...只得了20 TAT.C题骗分似乎有50 ..B题本来想骗分..然后/ ...

  9. GdiPlus 一个给 Delphi 提供的新的 GDI+ 接口很好用!

    尽管 GDI+ 已经有近 10 年的历史(随 Win2000 推出), 尽管 DirectX 如日中天, 但在 Windows 7 之前的版本下进行 2D 绘图还是离不开它, 微软也没有停止对它的升级 ...

  10. NX二次开发-UFUN移动工程图视图UF_DRAW_move_view

    #include <uf.h> #include <uf_draw.h> #include <uf_drf.h> #include <uf_obj.h> ...