C++利用动态数组实现顺序表(不限数据类型)
通过类模板实现顺序表时,若进行比较和遍历操作,模板元素可以通过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++利用动态数组实现顺序表(不限数据类型)的更多相关文章
- C语言利用动态数组实现顺序表(不限数据类型)
实现任意数据类型的顺序表的初始化,插入,删除(按值删除:按位置删除),销毁功能.. 顺序表结构体 实现顺序表结构体的三个要素:(1)数组首地址:(2)数组的大小:(3)当前数组元素的个数. //顺序表 ...
- "《算法导论》之‘线性表’":基于动态分配的数组的顺序表
我们利用静态分配的数组来实现的顺序表的局限还是挺大的,主要在于它的容量是预先定好的,用户不能根据自己的需要来改变.如果为了后续用户能够自己调整顺序表的大小,动态地分配数组空间还是很有必要的.基于动态分 ...
- "《算法导论》之‘线性表’":基于静态分配的数组的顺序表
首先,我们来搞明白几个概念吧(参考自网站数据结构及百度百科). 线性表 线性表是最基本.最简单.也是最常用的一种数据结构.线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外, ...
- 使用JAVA数组实现顺序表
1,引入了JAVA泛型类,因此定义了一个Object[] 类型的数组,从而可以保存各种不同类型的对象. 2,默认构造方法创建了一个默认大小为16的Object数组:带参数的构造方法创建一个指定长度的O ...
- HDU 2819 ——Swap——————【最大匹配、利用linker数组、邻接表方式】
Swap Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Status ...
- Java实现顺序表
利用顺序存储结构表示的顺序表称为顺序表. 它用一组连续的地址存储单元一次存放线性表中的数据元素. 顺序表的实现是数据结构中最简单的一种. 由于代码中已经有详细注释,代码外不再阐述. 下次再陈上关于顺序 ...
- 数据结构 单链表&顺序表
顺序表: 一般使用数组(C语言中的数组采用顺序存储方式.即连续地址存储)来描述. 优点:在于随机访问元素, 缺点:插入和和删除的时候,需要移动大量的元素. 链表: 优点:插入或删除元素时很方便,使用灵 ...
- 数据结构4:顺序表(线性表的顺序存储结构)及C语言实现
逻辑结构上呈线性分布的数据元素在实际的物理存储结构中也同样相互之间紧挨着,这种存储结构称为线性表的顺序存储结构. 也就是说,逻辑上具有线性关系的数据按照前后的次序全部存储在一整块连续的内存空间中,之间 ...
- c语言进阶12-线性表之顺序表
一. 线性表的定义 为什么要学习线性表呢? 因为我们日常生活中存在种数据关系,计算机程序是为了解决日常生活的数据关系,因此我们要学习线性表. 线性表是什么呢? 线性表是由n个元素组成的有限序列. 需 ...
随机推荐
- sanic中间件和监听器
一:中间件 中间件是服务器在请求之前或之后执行的功能,他们可以用来修改修改用户定义处理函数的请求或相应. Sanic提供两种类型的中间件:请求和响应. 两者都是使用@app.middleware装饰器 ...
- HTML 自定义元素教程
组件是 Web 开发的方向,现在的热点是 JavaScript 组件,但是 HTML 组件未来可能更有希望. 本文就介绍 HTML 组件的基础知识:自定义元素(custom elements). 文章 ...
- Flyway 学习时遇到的错误
错误一: No plugin found for prefix 'flyway' in the current project and in the plugin groups 找不到Flyway插 ...
- js的基本语法规范
1.不要在同一行声明多个变量: 2.使用===/!==来比较true/false的返回值: 3.使用字面量替代new Array这种形式: 4.不要使用全局函数: 5.switch语句必须带有defa ...
- Mac上Chrome浏览器跨域解决方案
现在比较新的浏览器在本地调试时AJAX请求,基本都会有跨域问题.相应的解决方案也挺多的,工具也不少.像charles等抓包工具等.不过最简单的就是移除浏览器的同源限制. 我们要做的第一步,就是创建一个 ...
- Shell [[]]详解:检测某个条件是否成立
[[ ]]是 Shell 内置关键字,它和 test 命令类似,也用来检测某个条件是否成立. test 能做到的,[[ ]] 也能做到,而且 [[ ]] 做的更好:test 做不到的,[[ ]] 还能 ...
- delphi xe10 麦克风、摄像头操作
TakePhotoFromCameraAction1: TTakePhotoFromCameraAction; // 通过手机摄像头获取图片TakePhotoFromLibraryAction1: T ...
- delphi xe10 中使用剪贴板(跨平台)
VCL 中如何使用剪贴板咱就不说了,FMX 做为一个新的框架,提供了跨平台的剪贴板支持.FMX 对剪贴板的支持来自两个接口: IFMXClipboardService:位于 FMX.Platform. ...
- HTML5布局篇
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...
- Go 程序开发的注意事项
Go 程序开发的注意事项 1) Go 源文件以 "go" 为扩展名. 2) Go 应用程序的执行入口是 main()函数. 这个是和其它编程语言(比如 java/c) ...