泛化动态数组

动态数组的核心思想是在存储数据时动态的管理数组元素占用的内存,通过调用动态数组的类方法来对数组中的数据进行增删改查操作。最初我们为数组申请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. [apue] 一个查看当前终端标志位设置的小工具

    话不多说,先看运行效果: >./term input flag 0x00000500 BRKINT not in ICRNL IGNBRK not in IGNCR not in IGNPAR ...

  2. 开始使用Manjaro

    Manjaro是什么? 一个基于Arch系列,开源的linux发行版 Mnajrao官网了解更多,这里不做更多阐述内容 为什么使用Manjaro 第一点,为了方便自己隔离腾讯网游 第二点,更方便的学习 ...

  3. 用HttpURLConnection来完成HTTP发送报文接收报文!

    public String sendMsg(String url, byte[] PostData) { String content = null; URL urls = null; try { u ...

  4. 解决谷歌浏览器设置font-family属性不起作用,(css中设置了font-family:没有用)css字体属性没用

    嗯,这个问题百思不得解.其他的浏览器器都没问题,在谷歌上就不行,网上找了很多,都没效果,后才发现,当然同样的问题可能错不一样的地方,我的解决方案: 感觉主要原因是自己也没查到,乱改一堆,就OK啦: 1 ...

  5. 什么是“跑面”呢? - ERSS耳斯百科:您的随身移动百科

    跑面 [pǎo miàn] 跑面,是一个汉语词汇,拼音为pǎo miàn,英文名为Run-Noodles,最基本解释为人跑步去吃面,其意义还有多重深层解释. 中文名:跑面 英文名:Run-Noodle ...

  6. 博客与微信小程序的同步

    在此之前,先说说自己最近的打算,才购买了阿里云的服务器,想做一个网站和图床网盘之类的方便自己使用. 考虑到小程序,又打算将自己的博客内容放到小程序中.从零开发实属困难,应该还要一段时间才能完成. 目前 ...

  7. copy and swap技巧与移动赋值操作符

    最近在实现一个Delegate类的时候碰到了一个问题,就是copy and swap技巧和移动赋值操作符有冲突. 比如有以下一个类: class Fun { public: Fun(const Fun ...

  8. GP工作室-团队项目Beta冲刺

    GP工作室-团队项目Beta冲刺 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/GeographicInformationScience/ 这个作业要求 ...

  9. OpenCV2.4.13+Qt5.6.2配置方法

    [1.环境变量] D:\Soft\OpenCV2\MinGW_build\bin; C:\Qt\Qt5.6.2\Tools\mingw492_32\bin; D:\Soft\Programming\C ...

  10. Android教程2020 - RecyclerView实际使用

    示例,用RecyclerView的item做出一个列表. Android教程2020 - 系列总览 本文链接 前面我们已经知道如何用RecyclerView显示一列数据.这里我们做出一个具体的例子.尽 ...