1.简介
顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。
顺序表 ArrayList 是对数组 object[] 的再次封装
相比于数组,顺序表的容量是可变的
2.这里我们尝试自己使用数组封装一个顺序表
using System; namespace DataStructure { /// <summary> /// 自定义顺序表 /// </summary> public class ArrayListDS { private const int _defaulCapacity = 4; //数组的初始容器 private object[] _items; // 存放数据的数组 private int _size = 0; // 元素个数 /// <summary> /// 无参构造函数,默认容量为0 /// </summary> public ArrayListDS() { this._items = new object[0]; } /// <summary> /// 带容量初始化构造函数 /// </summary> /// <param name="capacity"></param> public ArrayListDS(int capacity) { if (capacity < 0) throw new ArgumentOutOfRangeException("capacity", "数组长度不能为负数"); this._items = new object[capacity]; } /// <summary> /// 元素个数 /// </summary> public virtual int Count { get { return this._size; } } /// <summary> /// 容量 /// </summary> public virtual int Capacity { get { return this._items.Length; } set { if (value != this._items.Length) { if (value < this._size) throw new ArgumentOutOfRangeException("value", "容量太小了"); // 开辟一个新的内存空间存储元素 object[] destinationArray = new object[value]; if (this._size > 0) Array.Copy(this._items, 0, destinationArray, 0, this._size); this._items = destinationArray; } } } /// <summary> /// 判断扩容 /// </summary> private void EnsureCapacity() { // _items.Length是数组容量,_size是数组个数 if (this._items.Length == this._size) this.Capacity = this.Capacity + _defaulCapacity; } /// <summary> /// 判断超出索引 /// </summary> /// <param name="index">索引</param> private void OutIndex(int index) { if (index < 0 || index >= this._size) throw new ArgumentOutOfRangeException("index", "索引超出范围"); } /// <summary> /// 添加元素 /// </summary> /// <param name="value"></param> public virtual void Add(object value) { EnsureCapacity(); this._items[this._size] = value; this._size++; } /// <summary> /// 索引器,可获取值、修改值、新增值 /// </summary> /// <param name="index">索引</param> /// <returns></returns> public virtual object this[int index] { get { OutIndex(index); return this._items[index];//获取值 } set { if (index < 0 || index > this._size) throw new ArgumentOutOfRangeException("index", "索引超出范围"); if (index < this._size)//修改值 this._items[index] = value; if (index == this._size)//新增值 Add(value); } } /// <summary> /// 裁剪多余容量 /// </summary> public virtual void TrimToSize() { this.Capacity = this._size; } /// <summary> /// 删除指定索引的元素 /// </summary> /// <param name="index">索引</param> public virtual void RemoveAt(int index) { OutIndex(index); if (index < this._size - 1) { // 使删除元素后的所有元素向前移一位 Array.Copy(this._items, index + 1, this._items, index, this._size - index - 1); } // 最后一位置空 this._items[this._size - 1] = null; this._size--; } /// <summary> /// 插入 /// </summary> /// <param name="index"></param> /// <param name="value"></param> public virtual void Insert(int index, object value) { if (index < 0 || index > this._size) throw new ArgumentOutOfRangeException("index", "索引超出范围"); EnsureCapacity(); if (index < this._size) { // 插入点后面的元素后移一位 Array.Copy(this._items, index, this._items, index + 1, this._size - index); } this._items[index] = value; this._size++; } } }
3.ArrayList 和 List<T> 优劣对比
了解了ArrayList 的底层,我们知道它使用的是 object数组,会有装箱和拆箱的消耗
List<T> 使用了泛型,类型安全,比ArrayList 性能更优,不过在使用的过程中 只能指定一种类型。