动态数组
⚪数组是一种顺序存储的线性表,所有匀速的内存地址都是连续的
在很多编程语言中,数组都有个致命的缺点——无法动态修改容量
因此在实际开发中,我们希望数组的容量是可以动态改变的
⚪ 接口设计
int sizeOf(); //元素的数量
bool isEmpty(); //是否为空
bool contains(E elemnet); //是否包含某个元素
E get(int index); //返回index位置对应的元素
E set(int index, E element); //设置index位置的元素
void add(E element); //往尾节点添加元素
void add(int index, E element); //往index位置添加元素
E remove(int index); //删除index位置对应的元素
int indexOf(E element); //查看元素的位置
void clear(); //清除所有元素
void print(); //显示所有元素
下面是 ArrayList.h
文件。
#pragma once
#include <iostream>
using namespace std;
template <class E>
class ArrayList
{
private:
int size;
int *elements;
static const int DEFAULT_CAPACITY = 10;
static const int ELEMNT_NONE_FOUND = -1;
void EnsureCapacity(int capacity); //检查是否需要扩容
public:
ArrayList()
{
elements = new int[DEFAULT_CAPACITY];
}
ArrayList (E a[],int capaticy)
{
int n = capaticy;
capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy;
elements = new int[capaticy];
for (int i = 0; i < n; i++)
{
elements[i] = a[i];
}
size = n;
}
int sizeOf(); //元素的数量
bool isEmpty(); //是否为空
bool contains(E elemnet); //是否包含某个元素
E get(int index); //返回index位置对应的元素
E set(int index, E element); //设置index位置的元素
void add(E element); //往尾节点添加元素
void add(int index, E element); //往index位置添加元素
E remove(int index); //删除index位置对应的元素
int indexOf(E element); //查看元素的位置 若存在则返回对应位置,若不存在,则返回-1
void clear(); //清除所有元素
void print(); //显示所有元素
~ArrayList() {};
};
⚪易错分析
①删除元素
删除的元素应当分为2种情况来讨论
1、删除尾部元素
如果删除的是尾部元素,直接将size–,使用户不可调用尾部元素即可。
2、删除非尾部元素
假设size=7,index=3时
因为当初数组申请空间时,是向系统动态分配了capacity个连续的存储空间,所以不存在只删除某个元素,将其内存挖去的下面的这种情况。
正确的删除元素应当是元素的挪动。 根据下方图片的显示,我们能直观的看出来元素挪动了4、5、6位置的元素,将删除的元素后方的值往前挪一个,利用element[i-1]=element[i]语句,从前往后将后方元素的值覆盖前方元素的值。从4-6挪动了三次,而4就是index+1,6是size-1。因此元素的挪动范围就是[index+1,size-1],利用for(int i=index+1;i<=size-1;i++)循环来使用 ,最后再size–。
最后将第一种尾部元素删除的情况带入for循环的语句中发现也符合要求,因此只需要写出for循环的一般情况。
remove(int index)代码:
template <class E>
E ArrayList<E>::remove(int index) //删除index位置对应的元素
{
if (index < 1 || index >= size) throw"Index错误"; //检测index是否越界
int old = elements[index]; //保存被删除元素的值用来返回
for (int i = index + 1; i < size; i++)
{
elements[i - 1] = elements[i];
}
elements[size--]=NULL; //将element[size]=NUL和size-1的语句和的语句合并
return old;
}
②在某个位置添加元素
对于某个位置应当分3种情况来讨论
1、在头部添加元素
2、在中间添加元素
假设size=5,index=2
![原版数组](https://img-blog.csdnimg.cn/20200913110719376.png#pic_center)
![在中间添加元素](https://img-blog.csdnimg.cn/2020091311032611.png#pic_center)
这种情况就很类似于删除元素的思想,但是和删除元素的区别在于挪动的顺序,删除元素是从前往后挪,而添加元素是从后往前挪。如果是按照一样的挪动思想会出现下方图片的情况。
3、在尾部添加元素
直接在尾部添加元素,size++即可
⚠:此处要注意动态扩容的问题,首先要检查添加元素后是否超过了分配的数组长度。
template <class E>
void ArrayList<E>::EnsureCapacity(int capacity) //检查是否需要扩容
{
int oldCapacity = size;
if (oldCapacity >= capacity)
{
return;
}
int newCapacity = oldCapacity + (oldCapacity >> 1);
int* NewElements = new int[newCapacity];
for (int i = 0; i < size; i++)
{
NewElements[i] = elements[i];
}
elements = NewElements;
}
add(int index, E element)代码:
template <class E>
void ArrayList<E>::add(int index, E element) //往index位置添加元素
{
EnsureCapacity(size + 1); //检查是否需要扩容
if (index < 0 || index > size) throw"Index错误"; //检测index是否越界 此处是 index > size而不是index >= size 因为有可能是最后面插入元素
for (int i = size - 1; i >= index; i--)
{
elements[i + 1] = elements[i];
}
elements[index] = element;
size++;
}
🔔:不管是添加删除还是查找某一位置对应的元素都应该进行index的检测,防止数组越界
if(index < 0||index>=size) throw"Index错误"; //检测index是否越界
⚪总代码
ArrayList.h
#pragma once
#include <iostream>
using namespace std;
template <class E>
class ArrayList
{
private:
int size;
int *elements;
static const int DEFAULT_CAPACITY = 10;
static const int ELEMNT_NONE_FOUND = -1;
void EnsureCapacity(int capacity); //检查是否需要扩容
public:
ArrayList()
{
elements = new int[DEFAULT_CAPACITY];
}
ArrayList (E a[],int capaticy)
{
int n = capaticy;
capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy;
elements = new int[capaticy];
for (int i = 0; i < n; i++)
{
elements[i] = a[i];
}
size = n;
}
int sizeOf(); //元素的数量
bool isEmpty(); //是否为空
bool contains(E elemnet); //是否包含某个元素
E get(int index); //返回index位置对应的元素
E set(int index, E element); //设置index位置的元素
void add(E element); //往尾节点添加元素
void add(int index, E element); //往index位置添加元素
E remove(int index); //删除index位置对应的元素
int indexOf(E element); //查看元素的位置 若存在则返回对应位置,若不存在,则返回-1
void clear(); //清除所有元素
void print(); //显示所有元素
~ArrayList() {};
};
ArrayList.cpp
#include "ArrayList.h"
template <class E>
int ArrayList<E>::sizeOf() //元素的数量
{
return size;
}
template <class E>
bool ArrayList<E>::isEmpty() //是否为空
{
return size == 0;
}
template <class E>
bool ArrayList<E>::contains(E element) //是否包含某个元素
{
for (int i = 0; i < size; i++)
{
if (elements[i] == element)
{
return true;
}
}
return false;
}
template <class E>
E ArrayList<E>::get(int index) //返回index位置对应的元素
{
if (index < 0 || index >= size) throw "Index错误";//检测index是否越界
return elements[index];
}
template <class E>
E ArrayList<E>::set(int index, E element) //设置index位置的元素
{
if(index < 0 || index >= size) throw"Index错误"; //检测index是否越界
elements[index] = element;
return element;
}
template <class E>
void ArrayList<E>::add(E element)
{
add(size, element);
}
template <class E>
void ArrayList<E>::add(int index, E element) //往index位置添加元素
{
EnsureCapacity(size + 1); //检查是否需要扩容
if (index < 0 || index > size) throw"Index错误"; //检测index是否越界 此处是 index < 0 || index > size而不是index < 1 || index >= size 因为有可能是往最面前后者最后面插入元素
for (int i = size - 1; i >= index; i--)
{
elements[i + 1] = elements[i];
}
elements[index] = element;
size++;
}
template <class E>
E ArrayList<E>::remove(int index) //删除index位置对应的元素
{
if (index < 0 || index >= size) throw"Index错误"; //检测index是否越界
int old = elements[index];
for (int i = index + 1; i < size; i++)
{
elements[i - 1] = elements[i];
}
elements[--size]=NULL;
return old;
}
template <class E>
int ArrayList<E>::indexOf(E element) //查看元素的位置 若存在则返回对应位置,若不存在,则返回-1
{
for (int i = 0; i < size; i++)
{
if (elements[i] == element)
{
return i;
}
}
return ELEMNT_NONE_FOUND;
}
template <class E>
void ArrayList<E>::clear() //清除所有元素
{
for (int i = 0; i < size; i++)
{
elements[i] = NULL;
}
size = 0;
}
template <class E>
void ArrayList<E>::print()
{
for (int i = 0; i < size - 1; i++)
{
cout << i << ":" << elements[i] << " ";
}
}
template <class E>
void ArrayList<E>::EnsureCapacity(int capacity) //检查是否需要扩容
{
int oldCapacity = size;
if (oldCapacity >= capacity)
{
return;
}
int newCapacity = oldCapacity + (oldCapacity >> 1);
int* NewElements = new int[newCapacity];
for (int i = 0; i < size; i++)
{
NewElements[i] = elements[i];
}
elements = NewElements;
}
main.cpp
#include <iostream>
#include "ArrayList.h"
#include "ArrayList.cpp"
int main()
{
int r[5] = { 1,2,3,4,5 }, i, x; //建立具有5个元素的顺序表
ArrayList<int> list(r,5);
cout << "当前线性表的数据为:"; //输出当前线性表
list.print();
try
{
list.add(2, 8); //在第2个位置插入值为8的元素
cout << "执行插入操作后的数据为:";
list.print(); //插入后的顺序表 1 2 8 3 4 5
}
catch (char* str) { cout << str << endl; }
cout << "当前线性表的长度为:" << list.sizeOf() << endl; //输出线性表的长度 6
cout << "请输入查找的元素:";
cin >> x;
i = list.indexOf(x);
if (i == -1)cout << "查找失败" << endl;
else cout << "元素" << x << "的位置为:" << i << endl;
try
{
cout << "请输入查找第几个元素值:";
cin >> i;
cout << "第" << i << "个元素值是" << list.get(i) << endl;
}
catch (char* str) { cout << str << endl;
}
try
{
cout << "请输入要删除第几个元素:";
cin >> i;
x = list.remove(i); //删除第 i 个元素
cout << "删除的元素是" << x << ",删除后的数据为:";
list.print(); //输出删除后的线性表
}
catch (char* str) {cout << str << endl; }
return 0;
}
全部代码都通过测试,皆可放心食用