19自定义List集合并完成系统List的功能
自定义List
1在visual studio中创建一个类:MyList
代码如下:
public class MyList<T> : IEnumerable<T>//IEnumerable<T>这个接口用于实现延迟调用
{
类名后面跟<T>,表示可以传任意类型(泛型)
//集合内部的数组
private T[] array = new T[4];
//数组的索引
private int index;
/// <summary>
/// 实际条数
/// </summary>
public int Count
{
get
{
return index;
}
}
/// <summary>
/// 容量
/// </summary>
public int Capacity
{
get
{
return array.Length;
}
}
//把数据存到数组
public void Add(T t)
{
//获取数组长度
int length = array.Length;
if (index == length)
{
//对数组进行扩容
T[] newArray = new T[length * 2];
//把旧的值写入到新的数组
for (int i = 0; i < length; i++)
{
newArray[i] = array[i];
}
//将新数组赋值给旧数组,实际上这里是将栈中新的数组的引用也就是新数组的内存地址赋值给了array变量值里,
//旧数组还在,只不过在堆中没有引用指向它了
array = newArray;
}
//向数组里添加数据
array[index] = t;
//更新索引
index++;
}
/// <summary>
/// 根据索引对集合读写
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index]
{
get
{
return array[index];
}
set
{
array[index] = value;
}
}
/// <summary>
/// 根据内容移除第一个匹配项
/// </summary>
/// <param name="t">泛型</param>
public void Remove(T t)
{
#region 方法
////删除操作的状态
//bool state = true;
////创建一个新数组
//T[] newArray4 = new T[Capacity];
////用来标识新数组的下标
//int i2 = 0;
////循环查找原数组中要删除的值和
//for (int i = 0; i < index; i++)
//{
// //判断要删除的值是否为当前循环到的值
// if (array[i].Equals(t) && state)
// {
// state = false;
// continue;
// }
// //将到前循环到的值插入新数组中
// newArray4[i2] = array[i];
// i2++;
//}
////将新数组赋值给原数组
//array = newArray4;
////如果没有找到要删除的数据则下标不减,因为没有删除操作
//if (!state)
//{
// //原数组下标减减,因为移除了一个元素
// index--;
//}
#endregion
#region 老师的方法
//先查被删除的元素的下标,再调用根据下标删除的方法
RemoveAt(FindIndex(t));
#endregion
}
/// <summary>
/// 删除范围的元素
/// </summary>
/// <param name="begin"></param>
/// <param name="len"></param>
public void RemoveRange(int begin, int len)
{
if (len == 0)
{
return;
}
//循环将开始位置后面的元素往前移
for (int i = begin; i < Count - len; i++)//
{
array[i] = array[i + len];
}
index = Count - len;
}
/// <summary>
/// 返回某个元素的下标
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public int FindIndex(T t)
{
//被查找元素的索引
int poi = -1;
//循环遍历查找数组
for (int i = 0; i < Count; i++)
{
//判断当前循环到的值和t是否相等
if (array[i].Equals(t))
{
//将当前索引赋值给被查找元素的索引
poi = i;
//结束循环,因为找到了符合的元素就不需要查了
break;
}
}
if (poi == -1)//没找到报错
{
throw new Exception("删除的元素不存在");
}
//返回被查找的元素的索引
return poi;
}
/// <summary>
/// 根据索引移除指定项
/// </summary>
/// <param name="newIndex">要删除的索引</param>
public void RemoveAt(int newIndex)
{
#region 自己写的方法
////判断下标是否符合
//if (newIndex > index)
//{
// return;
//}
////删除操作的状态
//bool state = true;
////创建一个新数组
//T[] newArray4 = new T[Capacity];
////用来标识新数组的下标
//int i2 = 0;
////循环查找原数组中要删除的值和
//for (int i = 0; i < index; i++)
//{
// //判断要删除的下标的值是否为当前循环到的值
// if (array[i].Equals(array[newIndex]) && state)//只需要判断下标即可i==newIndex
// {
// state = false;
// continue;
// }
// //将到前循环到的值插入新数组中
// newArray4[i2] = array[i];
// i2++;
//}
////将新数组赋值给原数组
//array = newArray4;
////原数组下标减减,因为移除了一个元素
//index--;
#endregion
#region 老师写方法1
//判断
////这个写法分成删除前和删除后,并且用两个循环
////创建一个新数组,用于保存删除数据后的数组
//T[] newArray = new T[Capacity];//new T[Count]这里可以写
////删除前,循环将被删位置前面的元素赋值给新数组
//for (int i = 0; i < newIndex; i++)
//{
// //将被删位置前面的元素赋值给新数组
// newArray[i] = array[i];
//}
////删除后,将被删除元素后面的元素赋值给新数组,本质上就跳过了被删元素
//for (int i = newIndex; i < Count-1; i++)
//{
//count-1实际上会少循环一次,标准应该是循环count次,但是这里
//少循环一次也不影响,因为如果是删除数组中的最后一位则循环count-1刚好,
//而且还不用执行循环体进行判断啥的,循环不到最后一位则新数组里没有添加最后一位
//如果是删除数组前面的那少循环一次也能添加到最后一位,因为删除前面一位后的会往后跳一位
// //跳过被删元素,让其后面的元素赋值给新数组
// newArray[i] = array[i+1];
//}
////执行了删除操作,数组的实际长度减一
//index--;
////将新数组的引用赋值到在栈中存旧数组的引用的变量中
//array = newArray;
#endregion
#region 老师方法2
////写成一个循环
////创建一个新数组,用于保存删除数据后的数组
//T[] newArray = new T[Capacity];//new T[Count]这里可以写
////循环整个旧数组,当下标等于要删除的下标时,直接跳一位赋值到新数组即可
//for (int i = 0, j = 0; i < Count - 1; i++, j++)
//{
// //count-1实际上会少循环一次,标准应该是循环count次,但是这里
// //少循环一次也不影响,因为如果是删除数组中的最后一位则循环count-1刚好,
// //而且还不用执行循环体进行判断啥的,循环不到最后一位则新数组里没有添加最后一位
// //如果是删除数组前面的那少循环一次也能添加到最后一位,因为删除前面一位后的会往后跳一位
// //判断下标是否相等
// if (j == newIndex)
// {
// //使j往后面跳一位
// j++;
// }
// //将旧数组中的元素添加到新数组
// newArray[i] = array[j];
//}
////将新数组的引用赋值到在栈中存旧数组的引用的变量中
//array = newArray;
////执行了删除操作,数组的实际长度减一
//index--;
#endregion
#region 老师方法3
////循环数组,将要被删除的下标的后面的元素向前移一位,没有执行这个循环表示移除数组中最后一个值
//for (int i = newIndex; i < Count-1; i++)
//{
// //将被删除的下标后面的值往前移
// array[i] = array[i + 1];
//}
////处理最后一个值,可处理可不处理
//array[Count - 1] = default(T);
////实际条数减一
//index--;
#endregion
#region 老师方法4
//使用系统自带的方法创建数组
Array.Copy(array, newIndex + 1, array, newIndex, Count - newIndex - 1);
//处理最后一个值,可处理可不处理
array[Count - 1] = default(T);
//实际条数减一
index--;
#endregion
}
/// <summary>
/// 移除所有匹配项
/// </summary>
/// <param name="t"></param>
public void RemoveAll(T t)
{
#region 自己的方法
////被移除的元素的数量
//int cou = 0;
////创建一个新数组
//T[] newArray4 = new T[Capacity];
////用来标识新数组的下标
//int i2 = 0;
////删除操作的状态
//bool state = true;
////循环查找原数组中要删除的值和
//for (int i = 0; i < index; i++)
//{
// //判断要删除的值是否为当前循环到的值
// if (array[i].Equals(t))
// {
// state = false;
// cou++;
// continue;
// }
// //将到前循环到的值插入新数组中
// newArray4[i2] = array[i];
// //更新新数组的下标
// i2++;
//}
////将新数组赋值给原数组
//array = newArray4;
////如果没有找到要删除的数据则下标不减,因为没有删除操作
//if (!state)
//{
// //原数组下标减cou,因为移除了cou个元素
// index -= cou;
// //判断是否重新设置旧数组的长度
// if (array.Length / 2 >= index)
// {
// //创建一个新数组
// T[] newArray5 = new T[Capacity / 2];
// //将旧数组的值遍历赋值给新数组
// for (int i = 0; i < index; i++)
// {
// newArray5[i] = array[i];
// }
// //将新数组的引用给旧数组在栈中的变量
// array = newArray5;
// }
//}
#endregion
#region 老师的方法
for (int i = 0; i < Count; i++)
{
if (array[i].Equals(t))
{
RemoveAt(i);
//当从数组里移除一位,索引减1,不减下次不会检查被移除的元素索引,
//经过RemoveAt(i);方法后被移除的那个元素的下标会被后面一位元素填充
i--;
}
}
#endregion
}
public IEnumerator<T> GetEnumerator()
{
//throw new NotImplementedException();
//实现延迟调用,目的,实现自定义的list集合支持foreach循环
for (int i = 0; i < Count; i++)
{
yield return array[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
在外面类里实例化这个泛型类即可
//自己实现的list
MyList<string> strlist = new MyList<string>();