本片文章主要展现模仿List源码实现自定义List类,对理解C#有一定帮助。
基础内容
Add() 末尾添加元素
Insert() 指定下标插入元素
Count 属性表示元素个数
RemoveAt() 方法指定下标元素删除
IndexOf() 返回第一个元素所在下标
LastIndexOf() 返回最后一个元素所在下标
用泛型数组实现基本List
第一步定义MyList类
class MyList<T>
{
private T[] array;//泛型数组用来存储数据,作为类的主体
private int count = 0;//存储元素个数
public MyList(int size)
{
array = new T[size];
}
public MyList()
{
array = new T[0];
}
}
复制代码
完成类的初始化在此添加两个构造方法,不带参数的构造方法用来新建一个长度为0的数组,带参数的用来构建一个指定长度的数组。
//获取容量大小
public int Capacity { get => array.Length; }
public int Count { get => count; }
复制代码
设置访问器,并且对count字段进行封装,对象可以通过调用Count属性用来获取列表元素个数。
第二部实现Add方法
public void Add(T item)
{
if( Count == Capacity)//是否达到最大容量
{
if(Capacity == 0)
{
array = new T[4];
}
else
{
EnsureCapacity();
}
}
array[Count] = item;
count++;
}
private void EnsureCapacity()
{
//容量不够时,每次扩容一倍
var newArray = new T[Capacity * 2];
Array.Copy(array, newArray, Count);
array = newArray;
}
复制代码
当向数组中添加元素时出现容量不够,则以当前容量的两倍进行扩容。新建一个两倍长度的数组,然后将原数组成员拷贝到新数组。
添加索引器
希望列表对象能够像数组一样使用[]进行访问,就必须添加索引器。
//添加索引器
public T this[int index]
{
get { return array[index]; }
set { array[index] = value; }
}
复制代码
实现Insert方法
元素的插入方法需要理解一下,首先判断下标越界,其次容量容量足够才进行插入。
将从末尾到index处的元素逐个后移
将item赋值到index处
元素个数加一完成
//插入元素
public void Insert(int index,T item)
{
if (0 <=index && index <= Count)
{
if (Count == Capacity)
{
//容量不够需要扩容
EnsureCapacity();
}
//从后往前遍历
for (int i = Count-1; i >= index; i--)
{
array[i+1] = array[i];
}
array[index] = item;
count++;
}
else
{
throw new Exception("索引超出范围");
}
}
复制代码
实现RemoveAt方法
RemoveAt方法与Insert方法类似。
从index处开始逐个将元素前移
将最后一个元素设为默认值
元素个数减一
//删除指定元素
public void RemoveAt(int index)
{
if (0 <= index && index < Count)
{
for (int i = index+1; i < Count; i++)
{
array[i-1] = array[i];
}
array[Count - 1] = default(T);
count--;
}
else
{
throw new Exception("索引超出范围");
}
}
复制代码
实现查找方法
顺序遍历找到第一个相同元素,返回下标。泛型无法使用比较运算符进行比较。使用数组的Equals方法就好。
//顺序查找第一元素
public int IndexOf(T item)
{
for (int i = 0; i < Count; i++)
{
if (array[i].Equals(item))
{
return i;
}
}
return -1;
}
//逆序查找第一个元素
public int LastIndexOf(T item)
{
for (int i = Count-1; i >=0 ; i--)
{
if (array[i].Equals(item))
{
return i;
}
}
return -1;
}
复制代码
实现排序
使用最简的冒泡排序实现
在比较两个泛型元素时,使用CompaerTo方法,必须提供IComparable的泛型约束
class MyList<T> where T:IComparable{}
复制代码
//升序排序
public void Sort()
{
for (int i = 0; i < Count-1; i++)
{
for (int j = 0; j < Count-1-i; j++)
{
if (array[j].CompareTo(array[j + 1]) > 0)
{
T tempItem = array[j];
array[j] = array[j + 1];
array[j + 1] = tempItem;
}
}
}
}
复制代码
实现迭代器
利用yield简化迭代器,只用实现IEnumerable接口就行
class MyList<T>:IEnumerable<T> where T:IComparable{}
复制代码
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Count; i++)
{
yield return array[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
复制代码
清晰明了,这样便可以forch该列表对象了。
完整代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace DotNetStudy
{
class MyList<T>:IEnumerable<T> where T:IComparable
{
private T[] array;
private int count = 0;
public MyList(int size)
{
array = new T[size];
}
public MyList()
{
array = new T[0];
}
//获取容量大小
public int Capacity { get => array.Length; }
public int Count { get => count; }
public void Add(T item)
{
if( Count == Capacity)//是否达到最大容量
{
if(Capacity == 0)
{
array = new T[4];
}
else
{
EnsureCapacity();
}
}
array[Count] = item;
count++;
}
private void EnsureCapacity()
{
//容量不够时,每次扩容一倍
var newArray = new T[Capacity * 2];
Array.Copy(array, newArray, Count);
array = newArray;
}
public T GetItem(int index)
{
if(index>0 && index < Count)
{
return array[index];
}
else
{
//Console.WriteLine("索引超出范围");
throw new Exception("索引超出范围");
}
}
//添加索引器
public T this[int index]
{
get { return array[index]; }
set { array[index] = value; }
}
//插入元素
public void Insert(int index,T item)
{
if (0 <=index && index <= Count)
{
if (Count == Capacity)
{
//容量不够需要扩容
EnsureCapacity();
}
//从后往前遍历
for (int i = Count-1; i >= index; i--)
{
array[i+1] = array[i];
}
array[index] = item;
count++;
}
else
{
throw new Exception("索引超出范围");
}
}
//删除指定元素
public void RemoveAt(int index)
{
if (0 <= index && index < Count)
{
for (int i = index+1; i < Count; i++)
{
array[i-1] = array[i];
}
array[Count - 1] = default(T);
count--;
}
else
{
throw new Exception("索引超出范围");
}
}
//顺序查找第一元素
public int IndexOf(T item)
{
for (int i = 0; i < Count; i++)
{
if (array[i].Equals(item))
{
return i;
}
}
return -1;
}
//逆序查找第一个元素
public int LastIndexOf(T item)
{
for (int i = Count-1; i >=0 ; i--)
{
if (array[i].Equals(item))
{
return i;
}
}
return -1;
}
//升序排序
public void Sort()
{
for (int i = 0; i < Count-1; i++)
{
for (int j = 0; j < Count-1-i; j++)
{
if (array[j].CompareTo(array[j + 1]) > 0)
{
T tempItem = array[j];
array[j] = array[j + 1];
array[j + 1] = tempItem;
}
}
}
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Count; i++)
{
yield return array[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END