泛化动态数组

动态数组的核心思想是在存储数据时动态的管理数组元素占用的内存,通过调用动态数组的类方法来对数组中的数据进行增删改查操作。最初我们为数组申请10个元素的空间,放我们不断向数组中添加数据时,会自动的申请更大的空间(这里申请的是原本容量的1.5倍,用的是移位操作),将原来内存块的数据拷贝到新的更大的内存块中。当我们删除数据,当空闲内存是总容量的一半且不小于最小容量(10)时,将自动对数组内存缩容操作。

抽向数据类型(ADT) :(linearList.h)

/*************************************************************************
> File Name : linearList.h
> Author : Harold
> Mail : 2106562095@qq.com
> Github : www.github.com/Haroldcc
> Created Time : 2020年02月26日 11时02分58秒
************************************************************************/ /***** 线性表的抽象定义 *****/ #ifndef LINEARLIST_H
#define LINEARLIST_H #include <iostream> template <typename T>
class linearList
{
public:
virtual ~linearList() {}
virtual bool isEmpty() const = 0; //是否为空
virtual int size() const = 0; // 元素个数
virtual T &getElement(int index) const = 0; // 根据索引获取元素
virtual void setElement(int index, const T &element) = 0; // 根据索引更改元素值
virtual int indexOf(const T &element) const = 0; //指定元素第一次出现的索引
virtual void removeByIndex(int index) = 0; //根据索引删除元素并返回
virtual void removeByElement(const T &element) = 0; // 删除指定元素
virtual void add(const T &element) = 0; // 在尾部插入元素
virtual void add(int index, const T &element) = 0; // 在指定索引处插入元素
virtual void output(std::ostream &out) const = 0; // 插入输出流out
}; #endif

异常类(myException.h)

/*************************************************************************
> File Name : myExceptions.h
> Author : Harold
> Mail : 2106562095@qq.com
> Github : www.github.com/Haroldcc
> Created Time : 2020年02月26日 14时32分01秒
************************************************************************/ /***** 自定义的异常 *****/
#ifndef MYEXCEPTIONS_H
#define MYEXCEPTUONS_H #include <iostream>
#include <string> // 非法参数
class illegalParameterValue
{
private:
std::string message; public:
illegalParameterValue(std::string theMessage = "参数值非法!") : message(theMessage) {}
void outputMessage() { std::cout << message << std::endl; }
}; // 非法输入
class illegalInputData
{
private:
std::string message; public:
illegalInputData(std::string theMessage = "非法数据输入!")
{
message = theMessage;
} void outputMessage() { std::cout << message << std::endl; }
}; // 非法索引
class illegalIndex
{
private:
std::string message; public:
illegalIndex(std::string theMessage = "非法索引!") : message(theMessage) {}
void outputMessage() { std::cout << message << std::endl; }
};
#endif

动态数组头文件(arrayList.h)

/*************************************************************************
> File Name : arrayList.h
> Author : Harold
> Mail : 2106562095@qq.com
> Github : www.github.com/Haroldcc
> Created Time : 2020年02月26日 11时27分44秒
************************************************************************/
/***** 动态数组 *****/ #ifndef ARRAYLIST_H
#define ARRAYLIST_H #include "linearList.h"
#include "myExceptions.h"
#include <iostream>
#include <sstream> // for std::ostringstream template <typename T>
class arrayList : public linearList<T>
{
private:
// 检测索引是否越界
void checkIndex(int index) const;
// 数组扩容
void arrayListCapacityExpansion(T *&a, int oldCapacity, int newCapacity);
// 数组缩容
void arrayListCapacityReduce(); T *m_elements; // 数组元素
int m_capacity; // 数组容量
int m_size; // 元素个数 public:
// 构造函数,复制构造函数和析构函数
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T> &);
~arrayList() { delete[] this->m_elements; } // ADT方法
bool isEmpty() const { return this->m_size == 0; }
int size() const { return this->m_size; }
T &getElement(int index) const;
void setElement(int index, const T &element);
int indexOf(const T &element) const;
void removeByIndex(int index);
void removeByElement(const T &element);
void add(const T &element);
void add(int index, const T &element);
void output(std::ostream &out) const; // 其他方法
int capacity() const { return this->m_capacity; }
}; /*** 定义 ***/ template <typename T>
void arrayList<T>::checkIndex(int index) const
{
// 确定index在0和m_size - 1之间
if (index < 0 || index >= this->m_size)
{
std::ostringstream s;
s << "index = " << index << " size = " << this->m_size;
throw illegalIndex(s.str());
}
} template <typename T>
void arrayList<T>::arrayListCapacityExpansion(T *&a, int oldCapacity, int newCapacity)
{
if (newCapacity < 0)
{
throw illegalParameterValue("新容量必须 >= 0");
} T *temp = new T[newCapacity]; // 新数组
int number = std::min(oldCapacity, newCapacity); // copy的个数
std::copy(a, a + number, temp);
delete[] a; // 释放不在需要的就数组
a = temp; // 将新的数组赋给就数组指针
} template <typename T>
void arrayList<T>::arrayListCapacityReduce()
{
int oldCapacity = this->m_capacity;
int newCapacity = oldCapacity >> 1; // 容量减少为原来的一半 // 判断当size大于等于容量的一半或者容量小于等于默认容量,不需要缩容
if (this->m_size >= newCapacity || oldCapacity <= 10)
{
return;
} T *newElements = new T[newCapacity];
for (int i = 0; i < this->m_size; i++)
{
newElements[i] = this->m_elements[i];
}
delete[] m_elements; this->m_elements = newElements;
this->m_capacity = newCapacity;
} template <typename T>
arrayList<T>::arrayList(int initialCapacity)
{
if (initialCapacity < 1)
{
std::ostringstream s; // 构造新的字符串
s << "初始容量 = " << initialCapacity << "必须 > 0!";
throw illegalParameterValue(s.str());
}
this->m_capacity = initialCapacity;
this->m_elements = new T[this->m_capacity];
this->m_size = 0;
} template <typename T>
arrayList<T>::arrayList(const arrayList<T> &list)
{
this->m_capacity = list.m_capacity;
this->m_size = list.m_size;
this->m_elements = new T[this->m_capacity]; // // 将数据拷贝过去(STL算法)
// std::copy(list.element, list.element + this->m_size, this->element); for (int i = 0; i < this->m_size; i++)
this->m_elements[i] = list.m_elements[i];
} // 返回索引为index的元素,若不存在,抛出异常
template <typename T>
T &arrayList<T>::getElement(int index) const
{
checkIndex(index);
return this->m_elements[index];
} // 设置指定索引处的元素值
template <typename T>
void arrayList<T>::setElement(int index, const T &element)
{
checkIndex(index);
this->m_elements[index] = element;
} // 返回元素element第一次出现的索引,元素不存在,返回-1
template <typename T>
int arrayList<T>::indexOf(const T &element) const
{
// // 使用STL算法
// int elementIndex = (int)(std::find(this->element, this->element + this->m_size, element) - this->element); // if (elementIndex == this->m_size)
// {
// // 未找到
// return -1;
// }
// else
// {
// return elementIndex;
// } // 遍历寻找元素
for (int i = 0; i < this->m_size; i++)
if (this->m_elements[i] == element)
return i; return -1;
} // 删除索引为 index 的元素,若元素不存在,抛出illegalIndex异常
template <typename T>
void arrayList<T>::removeByIndex(int index)
{
checkIndex(index); // // STL算法
// // 有效索引,移动其索引大于index的元素
// std::copy(this->element + index + 1, this->element + this->m_size, this->element + index); for (int i = index + 1; i < this->m_size; i++)
{
this->m_elements[i - 1] = m_elements[i];
} this->m_elements[--this->m_size].~T(); // 调用析构函数 // 是否需要缩容
arrayListCapacityReduce();
} template <typename T>
void arrayList<T>::removeByElement(const T &element)
{
removeByIndex(indexOf(element));
} template <typename T>
void arrayList<T>::add(const T &element)
{
add(this->m_size, element);
} // 在索引 index 处插入元素 element
template <typename T>
void arrayList<T>::add(int index, const T &element)
{
if (index < 0 || index > this->m_size) // 无效索引
{
std::ostringstream s;
s << "index = " << index << " size = " << this->m_size;
throw illegalIndex(s.str());
} // 判断是否有足够容量’
if (this->m_size == this->m_capacity)
{
int oldCapacity = this->m_capacity;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 数组中元素个数等于容量,再添加需要扩容
// 这里设置每次增加的容量是之前容量的1.5倍
arrayListCapacityExpansion(this->m_elements, oldCapacity, newCapacity);
this->m_capacity = newCapacity;
} // 将数组元素向右迁移
for (int i = this->m_size - 1; i >= index; i--)
{
this->m_elements[i + 1] = this->m_elements[i];
}
this->m_elements[index] = element; this->m_size++;
} // 将arrayList放入输出流
template <typename T>
void arrayList<T>::output(std::ostream &out) const
{
for (int i = 0; i < this->m_size; i++)
{
out << this->m_elements[i] << " ";
}
} // 重载 <<
template <typename T>
std::ostream &operator<<(std::ostream &out, const arrayList<T> &list)
{
list.output(out);
return out;
}
#endif

测试代码

#include "arrayList.h"
#include "linearList.h"
#include <iostream> using namespace std; int main()
{
// 测试构造函数
linearList<double> *x = new arrayList<double>(20);
arrayList<int> y(2), z; // test capacity
cout << "Capacity of x, y and z = "
<< ((arrayList<double> *)x)->capacity() << ", "
<< y.capacity() << ", "
<< z.capacity() << endl; // test size
cout << "Initial size of x, y, and z = "
<< x->size() << ", "
<< y.size() << ", "
<< z.size() << endl; // test isEmpty
if (x->isEmpty())
cout << "x is isEmpty" << endl;
else
cout << "x is not isEmpty" << endl;
if (y.isEmpty())
cout << "y is isEmpty" << endl;
else
cout << "y is not isEmpty" << endl; // test add
y.add(0, 2);
y.add(1, 6);
y.add(0, 1);
y.add(2, 4);
y.add(3, 5);
y.add(2, 3);
cout << "added 6 integers, list y should be 1 2 3 4 5 6" << endl;
cout << "Size of y = " << y.size() << endl;
cout << "Capacity of y = " << y.capacity() << endl;
if (y.isEmpty())
cout << "y is isEmpty" << endl;
else
cout << "y is not isEmpty" << endl;
y.output(cout);
cout << endl
<< "Testing overloaded <<" << endl;
cout << y << endl; // test indexOf
int index = y.indexOf(4);
if (index < 0)
cout << "4 not found" << endl;
else
cout << "The index of 4 is " << index << endl; index = y.indexOf(7);
if (index < 0)
cout << "7 not found" << endl;
else
cout << "The index of 7 is " << index << endl; // test getElement
cout << "Element with index 0 is " << y.getElement(0) << endl;
cout << "Element with index 3 is " << y.getElement(3) << endl; // test removeByIndex
y.removeByIndex(1);
cout << "Element 1 erased" << endl;
cout << "The list is " << y << endl;
y.removeByIndex(2);
cout << "Element 2 erased" << endl;
cout << "The list is " << y << endl; cout << "Size of y = " << y.size() << endl;
cout << "Capacity of y = " << y.capacity() << endl;
if (y.isEmpty())
cout << "y is isEmpty" << endl;
else
cout << "y is not isEmpty" << endl; try
{
y.add(-3, 0);
}
catch (illegalIndex e)
{
cout << "Illegal index exception" << endl;
cout << "add index must be between 0 and list size" << endl;
e.outputMessage();
} // test copy constructor
arrayList<int> w(y);
y.removeByIndex(0);
y.removeByIndex(0);
cout << "w should be old y, new y has first 2 elements removed" << endl;
cout << "w is " << w << endl;
cout << "y is " << y << endl; // a few more adds, just for fun
y.add(0, 4);
y.add(0, 5);
y.add(0, 6);
y.add(0, 7);
cout << "y is " << y << endl; return 0;
}

输出

Capacity of x, y and z = 20, 2, 10
Initial size of x, y, and z = 0, 0, 0
x is isEmpty
y is isEmpty
added 6 integers, list y should be 1 2 3 4 5 6
Size of y = 6
Capacity of y = 6
y is not isEmpty
1 2 3 4 5 6
Testing overloaded <<
1 2 3 4 5 6
The index of 4 is 3
7 not found
Element with index 0 is 1
Element with index 3 is 4
Element 1 erased
The list is 1 3 4 5 6
Element 2 erased
The list is 1 3 5 6
Size of y = 4
Capacity of y = 6
y is not isEmpty
Illegal index exception
add index must be between 0 and list size
index = -3 size = 4
w should be old y, new y has first 2 elements removed
w is 1 3 5 6
y is 5 6
y is 7 6 5 4 5 6

C++泛化动态数组的更多相关文章

  1. 常用数据结构-线性表及Java 动态数组 深究

    [Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...

  2. C语言 · 动态数组的使用

    从键盘读入n个整数,使用动态数组存储所读入的整数,并计算它们的和与平均值分别输出.要求尽可能使用函数实现程序代码.平均值为小数的只保留其整数部分. 样例输入: 5 3 4 0 0 2样例输出:9 1样 ...

  3. C++中关于[]静态数组和new分配的动态数组的区别分析

    这篇文章主要介绍了C++中关于[]静态数组和new分配的动态数组的区别分析,很重要的概念,需要的朋友可以参考下 本文以实例分析了C++语言中关于[]静态数组和new分配的动态数组的区别,可以帮助大家加 ...

  4. C++之动态数组

    C99支持一种名为变长数组的结构来方便程序员.C++也提供了一种长度可在程序运行时确定的数组类型:动态数组.声明格式为:(声明 int 类型的数组) ; //此处可修改 ArraySize 的值 in ...

  5. VB默认属性、动态数组、Range对象的默认属性的一点不成熟的想法

    1.默认属性 VB6.0有默认属性的特性.当没有给对象指定具体的属性时,"默认属性"是VB6.0将使用的属性.在某些情形下,省略常用属性名,使代码更为精简. 因为CommandBu ...

  6. C#有关数组内存的释放及动态数组问题

    一.数组内存释放问题 数组内存的释放可以按照如下语句实现: string [] aa=new string[2]; aa[0]="A"; aa[1]="B"; ...

  7. (待续)C#语言中的动态数组(ArrayList)模拟常用页面置换算法(FIFO、LRU、Optimal)

    目录 00 简介 01 算法概述 02 公用方法与变量解释 03 先进先出置换算法(FIFO) 04 最近最久未使用(LRU)算法 05 最佳置换算法(OPT) 00 简介 页面置换算法主要是记录内存 ...

  8. C++ 动态数组实例

    一维动态数组的实例: #include <iostream> using namespace std; int main() { int *arr; int n; cout<< ...

  9. C++动态数组

    一: 一维数组初始化 标准方式1:int value[100]; //value[i]的值不定,因为没有初始化:标准方式2:int value[100] = {1,2,3}; //value[0],v ...

随机推荐

  1. 全网最详细!Centos7.X 搭建Grafana+Jmeter+Influxdb 性能实时监控平台

    背景 日常工作中,经常会用到Jmeter去压测,毕竟LR还要钱(@¥&*...),而最常用的接口压力测试,我们都是通过聚合报告去查看压测结果的,然鹅聚合报告的真的是丑到家了,作为程序猿这当然不 ...

  2. Spring(三)核心容器 - ApplicationContext 上下文启动准备

    目录 前言 正文 第一步:prepareRefresh 第二步:obtainFreshBeanFactory 第三步:prepareBeanFactory 第四步:postProcessBeanFac ...

  3. centOS7.1安装nginx与可能遇见的问题

    一,安装nginx(系统:CentOS7.1) 1.Nginx下载地址:http://nginx.org/download/nginx-1.6.2.tar.gz [root@linux src]# c ...

  4. TryCatchFinallyReturn

    public class TryCatchFinallyReturnTest { public int test(){ try { int i=1; int j=2/i; return 1; }cat ...

  5. 使用Razor表达式 举数组和集合 精通ASP-NET-MVC-5-弗瑞曼

  6. ios--->OC中Protocol理解及在代理模式中的使用

    OC中Protocol理解及在代理模式中的使用 Protocol基本概念 Protocol翻译过来, 叫做"协议",其作用就是用来声明一些方法: Protocol(协议)的作用 定 ...

  7. linux--->PHP常用模块解析

    PHP常用模块解析 php-gd :GD库是php处理图形的扩展库,GD库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片,也可以给图片加水印 php-ldap :LDAP是轻量 ...

  8. Nginx(二) 常用配置

    全局配置段 # 允许运行nginx服务器的用户和用户组 user www-data; # 并发连接数处理(进程数量),跟cpu核数保存一致: worker_processes auto; # 存放 n ...

  9. Kubernetes 服务自动发现CoreDNS

    前言 Service服务,是一个概念,逻辑通过selector标签代理指定后端pod.众所周知,pod生命周期短,状态不稳定,pod错误异常后新生成的Pod IP会发生变化,之前Pod的访问方式均不可 ...

  10. 8、OSPF

    OSPF ---最短路径优先 用于在单一自治系统(Autonomous System-AS)内决策路由 自制系统(AS)AS: 执行统一路由策略的一组网络设备的组合可适应大规模的网络: ·    路由 ...