当前位置:网站首页>C# 自定义集合
C# 自定义集合
2022-07-23 05:45:00 【LKZღ木子李】
自定义集合,实现和List一样的功能! 实现了动态数组,自动缩容和扩容
下面时自己实现源码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestDataStruct
{
/// <summary>
/// 动态数组
/// </summary>
/// <typeparam name="T"></typeparam>
public class DynamicArray<T>: IList<T>, ICollection<T>, IEnumerator<T>, IEnumerator, IReadOnlyCollection<T>, IReadOnlyList<T>
{
/// <summary>
/// 数组
/// </summary>
private T[] arr;
/// <summary>
/// 数组中有多少元素
/// </summary>
private int N;
/// <summary>
/// 数组的容量
/// </summary>
private int capacity;
/// <summary>
/// 迭代器光标位置
/// </summary>
private int position;
/// <summary>
/// 数组的容量
/// </summary>
public int Capacity => capacity;
/// <summary>
/// 数组的元素个数
/// </summary>
public int Count => N;
public bool IsReadOnly => false;
public object Current => arr[position];
T IEnumerator<T>.Current => arr[position];
/// <summary>
/// 构造
/// </summary>
/// <param name="capacity_Temp">刚开始有多少容量</param>
public DynamicArray(int capacity_Temp)
{
arr = new T[capacity_Temp];
capacity = capacity_Temp;
N = 0;
}
/// <summary>
/// 构造,默认开启10个容量
/// </summary>
public DynamicArray() : this(10) {
}
/// <summary>
/// 构造
/// </summary>
/// <param name="ienumerable">存储那些元素,是一个迭代器</param>
public DynamicArray(IEnumerable<T> ienumerable)
{
arr = ienumerable.ToArray();
capacity = arr.Length;
N = capacity;
}
public T this[int index]
{
get
{
if (index > N)
{
ThrowError("索引超出索引");
}
return arr[index];
}
}
T IList<T>.this[int index]
{
get => this[index];
set
{
this.Insert(index, value);
}
}
/// <summary>
/// 添加元素
/// </summary>
/// <param name="e">需要添加的元素</param>
public void Add(T e)
{
arr[N] = e;
N++;
if (N == capacity)
{
ResetCapacity(capacity * 2);
}
}
/// <summary>
/// 插入元素
/// </summary>
/// <param name="index">在那个索引插入元素</param>
/// <param name="e">需要添加的元素</param>
public void Insert(int index, T e)
{
if (index >= capacity)
ThrowError("索引需要在容量范围内");
for (int i = N; i > index; i--)
{
arr[i] = arr[i - 1];
}
arr[index] = e;
N++;
/* 1,8,4,3,146,49 元素 如果要在8后面插入一个元素,就是再索引2插入一个元素 8后面的所有的元素都要往后面移动一位 */
//扩容
if (N == capacity)
{
ResetCapacity(capacity * 2);
}
}
/// <summary>
/// 判断动态数组中是否包含元素
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public bool Contains(T t)
{
return Contains(t, out int index);
}
/// <summary>
/// 判断动态数组中是否包含元素
/// </summary>
/// <param name="e">需要判断的元素</param>
/// <param name="index">那个元素在数组中的索引,不存在返回-1</param>
/// <returns></returns>
public bool Contains(T e, out int index)
{
index = -1;
for (int i = 0; i < N; i++)
{
if (arr[i].Equals(e))
{
index = i;
return true;
}
}
return false;
}
/// <summary>
/// 查找这个值在数组中的索引
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int IndexOf(T item)
{
Contains(item, out int index);
return index;
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public void RemoveAt(int index)
{
bool isLegal = N > index;
if (isLegal)
{
for (int i = index; i < N; i++)
{
arr[i] = arr[i + 1];
}
N--;
//缩容
if (N <= capacity/4)
{
ResetCapacity(capacity / 2);
}
}
/* 1,8,4,3,146,49 元素 如果删除8这个元素 8后面的元素都需要往前面移动 这个遍历多一个,就会把后面的默认值覆盖前面这个 */
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public bool Remove(T e)
{
bool isContains = Contains(e, out int index);
if (isContains)
{
RemoveAt(index);
}
return isContains;
}
/// <summary>
/// 重置数组容量
/// </summary>
/// <param name="newCapacity">要扩展的容量</param>
private void ResetCapacity(int newCapacity)
{
T[] temp = new T[newCapacity];
Array.Copy(arr, 0, temp, 0, N);
arr = temp;
this.capacity = newCapacity;
}
public void Clear()
{
Array.Clear(arr, 0, N);
N = 0;
}
public void CopyTo(T[] array, int arrayIndex)
{
Array.Copy(arr, array, arrayIndex);
}
public IEnumerator<T> GetEnumerator()
{
Reset();
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
Reset();
return this;
}
public bool MoveNext()
{
return ++position < N;
}
public void Reset()
{
position = -1;
}
public void Dispose()
{
Reset();
}
/// <summary>
/// 抛出异常
/// </summary>
/// <param name="message"></param>
private void ThrowError(string message)
{
throw new ArgumentException(message);
}
}
}
- 优缺点:
优点
可以添加数据动态扩容数组,跟List效果一样
缺点:
如果在添加数据中间插入或者是头部插入,这个性能耗时很高的,因为在这个位置插入后面的位置都需要移位,如果在尾端插入就不会
如果删除一个数据,这个数据在中间或者在头部,后面的所有数据都要往前移位,这个性能耗时很高的
解决方法
使用链表存储,解决这个问题
自定义链表
关注微信公众号【浪子独白】 获得更多精彩内容!
边栏推荐
- 常见的排序方法—选择排序
- 3.2daydayup draw inferences from one instance: three days of fishing and two days of net learning
- hot 100 动态规划
- C语言数据库:基于tcp多进程的在线词典,有详细的步骤已经图解,欢迎大家来观看
- B树 和 B+树
- (1)ASIO
- 5.4 Pyinstaller库安装与使用
- The CUDA version of pytorch installed by anconda is inconsistent with the CUDA version of the system
- vscode配置
- 0最短路径问题 LeetCode743. 网络延迟时间
猜你喜欢

博客搭建二:NexT主题相关设置beta

Blog building five: drawing bed selection

Question bank of basic principles of steel structure

用单向链表实现 队列

A comprehensive and detailed summary of the basic principles of steel structure
Blog building I: Framework selection

Using one-way linked list to realize queue

【Autosar 存储Stack NVM】
![[learning summary]](/img/f6/5f960052735a98057f66b7d186b53f.png)
[learning summary]

Blog building six: the method of binding your own domain name
随机推荐
5.4 Pyinstaller库安装与使用
配置历史版本Detectron遇到的问题
【学习总结】
Unity3D高清渲染管线无法在模型上播放视频
基于UDP的群聊聊天室
Mutual implementation of queue and heap (pure C implementation)
[introduction to AUTOSAR com 4.com service layer module]
【无标题】
Upper and lower case letter conversion
基于对象(Object Based)-两个经典类
C语言:详细讲解基于tcp和udp的两种本地通信方式
Basic OJ exercise of binary tree-
Prometheus Operator使用指南笔记
匿名上位机v7波形显示
大小写字母转换
VS属性配置相关知识
博客搭建二:NexT主题相关设置beta
[AUTOSAR com 1. introduction to communication protocol stack]
桌面远程协议-编解码
TeX or LaTeX or MikTeX or TeX Live or CTeX