list容器和数组的区别
数组
1、数组的长度固定,存满后不能再添加新的元素
2、数组无法得知当前已经存了几个元素,还剩多少空间
3、数组是一段连续的存储空间,确定后无法修改地址list容器
1、长度不固定,可以无限制添加新的元素
2、list容器可以得知当前已经存了多少个元素
3、list可以是不连续的存储空间
IMList
namespace List容器
{
interface IMyList
{
//接口的作用
//1、为后面要写的内容提供一个强制的模板,规范代码
//2、作为一个提纲的作用,为后面要写的内容提供思路
//3、提高写代码的效率
//增
void Add(T t);
void Insert(int index, T t);
//删
void Remove(T t);
void RemovedAll(T t);
void RemoveAt(int index);
//改
//查
T this[int index]
{
get;
set;
}
//获取容器的长度
int Count { get; }
}
}
接口中定义了,增、删、改、查四类函数,还有获取容器长度的get访问器
增:Add(T t) : 插入一个元素
Insert(int index, T t):按下标插入一个元素
删:Remove(T t)删除一个元素
RemoveAll(T t) 删除所有的跟这个元素相等的
RemoveAt(int index) 按下标删除
查 this[int index]: 索引器
MyList :
namespace List容器
{
class MyList : IMyList
{
//保存数据的数组
T[] data;
//游标
int count;
//无参构造:初始一个数组长度为4的容器
//count表示数组的长度,开始为0
public MyList(){
data = new T[4];
count = 0;
}
//有参构造:自定义容器的初始长度
public MyList(int capacity)
{
data = new T[capacity];
count = 0;
}
//索引器
//可以实现按下标查找元素,和按下标修改元素
public T this[int index] {
get
{
if(index >= count || index < 0)
{
throw new Exception("索引越界");
}
else
{
return data[index];
}
}
set
{
if (index >= count || index < 0)
{
throw new Exception("索引越界");
}
else
{
data[index] = value;
}
}
}
public int Count => count;
//在末增加元素
//添加元素:先校验容器的游标的长度是否大于或等于数组的长度,如果是,则创建一个新的数组长度是原来的两倍,同过循环将原数组的元素存入新数组。
public void Add(T t)
{
if (count >= data.Length)
{
T[] newdata = new T[data.Length * 2];
for (int i = 0; i < data.Length; i++)
{
newdata[i] = data[i];
}
//Array.Copy();
//1、改变data的指向,让data指向newdata
//2、原来的数组被标记为GC,系统自动清理
//3、newdata出了作用域之后也不存在了
data = newdata;
}
data[count] = t;
count++;
}
//插入
//首先校验传入的下标是否越界
//要考虑的几种情况
//1.下标越界
//2.下标与原数组长度一样
//3.下标小于数组长度
public void Insert(int index, T t)
{
if (index > count || index < 0)
{
throw new Exception("插入元素时索引越界");
}
//如果插入的元素下标与当前数组长度一致
//插入的思想:创建一个新数组,长度是原数组的两倍,先将原数组循环存入新数组
if ((count >= data.Length || index == count)
{
T[] newdata = new T[data.Length * 2];
for (int i = 0; i < index; i++)
{
newdata[i] = data[i];
}
for(int j = count; j > index; j--)
{
newdata[j] = data[j - 1];
}
newdata[index] = t;
data = newdata;
count++;
}
//如果下标小于原数组长度
//先将下标后面的元素的元素往后移动一位,然后将该元素插入进去
if(count < data.Length && index > 0 && index < count)
{
for (int j = count - 1; j > index; j--)
{
data[j] = data[j - 1];
}
data[index] = t;
count++;
}
}
//移除
//循环遍历整个容器,找到对应的元素的下标,然后将后面所有的元素往前移动一位
public void Remove(T t)
{
for (int i = 0; i < count ; i++)
{
if(t .Equals(data[i]))
{
for(int j = i; j < count - 1; j++)
{
data[j] = data[j + 1];
break;
}
}
}
count--;
}
//按照下标移除
//先校验下标是否越界,然后将传入下标的后面的元素全往前移动一位
public void RemoveAt(int index)
{
if (index >= count || index < 0)
{
throw new Exception("插入元素时索引越界");
}
else
{
for (int i = index; i < count - 1; i++)
{
data[i] = data[i + 1];
}
count--;
}
}
//public void RemovedAll(T t)
//{
// int i = 0;
// while(i < count)
// {
// if (t.Equals(data[i]))
// {
// for (int j = i; j < count - 1; j++)
// {
// data[j] = data[j+ 1];
// }
// count--;
// i--;
// }
// i++;
// }
//}
//删除所有的跟这个元素相等的
//循环列表中所有的元素,只要遇到跟t相同的,就将后面的元素往前面移动一位
public void RemovedAll(T t)
{
for(int i =0; i < count; i++)
{
if (t.Equals(data[i]))
{
for (int j = i; j < count - 1; j++)
{
data[j] = data[j + 1];
}
count--;
i--;
}
}
}
}
}
思考:
1.在用数组封装list容器时,要注意的问题是,下标越界的问题。
2.容器的封装一般包含几个重要的组成部分:增删改查的方法,索引器



