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个元素组成的有限序列. 需 ...
随机推荐
- CSS3-2d3d
1.过渡(transition)操作谁,给谁加过渡 transition:要过渡的属性 花费时间 运动曲线 何时开始: 多组属性变化,还是用 逗号 隔开 transition ...
- webpack初始化
1. 安装node js 2. 安装npm 3. 在桌面新建一个文件夹 4.利用cmd 进入文件夹 5.在cmd中创建一个新文件夹并且进入 6.npm init -y 生成page.json 7. ...
- vagrant ssh try
Vagrantfile add Vagrant.configure("2") do |config| config.vm.network "private_network ...
- jq-demo-轮播图
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- redis安装到本地服务的方法
要安装Redis,首先要获取安装包. Windows的Redis安装包需要到以下GitHub链接找到. 链接:https://github.com/MSOpenTech/redis 打开网站后,找到R ...
- webpack4.0基础
安装 yarn add webpack webpack-cli -D npx webpack index.js 图片 file-loader module: { rules: [ { test: /\ ...
- python编程语言学习day05(1)
模块(不起与python相关模块的名字) 1.random random.random() 在0与1之间取随机数 random.randint(a,b) 在a,b之间取随机整数,包括边界 ra ...
- Oozie安装
Oozie的安装与部署 1.解压Oozie $ tar -zxf /opt/softwares/oozie-4.0.0-cdh5.3.6.tar.gz -C /opt/modules/cdh/ 2.H ...
- 探索NDIS HOOK新的实现方法(1)
NDIS HOOK是专业级防火墙使用的一种拦截技术,NDIS HOOK的重点是如何获得特定协议对应NDIS_PROTOCOL_BLOCK指针,获得了该指针,接下来就可以替换该协议所注册的收发函数,而达 ...
- var 更明确地表示一个变量被设置为零值
创建一个变量并被初始化其为零值,习惯使用关键字var.这种做法是为了更明确地表示一个变量被设置为零值. 如果变量被初始化为某个非零值,就配合结构字面量和短变量操作符来创建变量. 零值 数值类型:0 字 ...