通过类模板实现顺序表时,若进行比较和遍历操作,模板元素可以通过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. jenkins构建结果企业微信提醒

    每当jenkin在构建之后我们想把构建结果SUCCESS/FAILURE或者其他信息通知给其他人,也许有人会说,不是有邮件提醒吗?但是我这里的环境邮件提醒的话所被通知者并不会第一时间去阅读,所以我们用 ...

  2. Promise 解决同步请求问题

    在写小程序和vue项目中,由于 api 不提供 同步请求,因此,可以通过  Promise 来实现 同步请求操作 在这里 对于 Promise 不太了解的小伙伴 可以查找 Promise 的api 文 ...

  3. 引入CSS样式表(书写位置)

    CSS可以写到那个位置? 是不是一定写到html文件里面呢? 内部样式表 内嵌式是将CSS代码集中写在HTML文档的head头部标签中,并且用style标签定义,其基本语法格式如下: <head ...

  4. Dart编程变量

    变量是"存储器中的命名空间",用于存储值.换句话说,它作为程序中值的容器.变量名称称为标识符.以下是标识符的命名规则 - 标识符不能是关键字. 标识符可以包含字母和数字. 标识符不 ...

  5. 经典单调栈最大子矩形——牛客多校第二场H

    题目是求次大子矩形,那么在求最大子矩形的时候维护M1,M2即可 转移M2时比较的过程要注意一下 #include<bits/stdc++.h> using namespace std; # ...

  6. 线性dp(记忆化搜索)——cf953C(经典好题dag和dp结合)

    非常好的题!和spoj 的 Mobile Service有点相似,用记忆化搜索很容易解决 看了网上的题解,也是减掉一维,刚好可以开下数组 https://blog.lucien.ink/archive ...

  7. NX二次开发-设置尺寸的附加尺寸UF_DRF_set_appended_text

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

  8. NX二次开发-UFUN获取NX系统默认导出CGM的选项设置UF_CGM_ask_default_export_options

    文章转载自唐康林NX二次开发论坛,原文出处: http://www.nxopen.cn/thread-126-1-1.html 刚才有同学问到这个问题,如果是用NXOpen来做,直接录制一下就可以了: ...

  9. NX二次开发-UFUN工程图表格注释写入文本内容UF_TABNOT_set_cell_text

    NX9+VS2012 #include <uf.h> #include <uf_tabnot.h> #include <NXOpen/Part.hxx> #incl ...

  10. 2018-06-05(thinking in java)

    1:类只能有2种访问权限,一种是不写访问权限:默认包访问权限,另一种是public.且类只能有一个pubic 2:方法有4种访问权限,pubic(都可以访问),protexted(继承访问权限),pr ...