数据结构之——动态数组完备版(C++实现)

动态数组

⚪数组是一种顺序存储的线性表,所有匀速的内存地址都是连续的

在很多编程语言中,数组都有个致命的缺点——无法动态修改容量
因此在实际开发中,我们希望数组的容量是可以动态改变的

⚪ 接口设计

    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;
}

全部代码都通过测试,皆可放心食用

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GXM.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值