C#线性顺序表SequencedList,模拟List<T>

线性数据结构是一组具有某种共性的数据结构按照某种逻辑上的顺序关系组成的一个数据集合。

线性表(Linear List)的基本操作主要有:

(1)Initialize:初始化,一般都是多种构造函数重载

(2)Get/Set:访问,获取或者设置指定位置的元素

(3)Count:当前集合的元素个数

(4)Add/Insert:插入一个或多个元素操作,将自动更新Count。注意,当临时数组空间(容量Capacity)不足时,一般对数组的长度双倍扩充,同时将当前数组元素复制到新的双倍长度数组中。

(5)Remove:移除一个或多个元素操作,将自动更新Count

(6)Search:查找指定条件或者索引的元素

(7)Traversal:遍历,一般来说实现IEnumerable接口

C#已经定义了泛型线性表List<T>类,其本质就是对数组的扩充操作,

微软 System.Collections.Generic.List<T> 链表类源代码:

System.Collections.Generic.List<T> 

本文自定义一个顺序表SequencedList,来模拟ist<T>。

新建控制台应用程序SequencedListDemo(VS2019新建.net 5.0程序)

新建类文件SequencedList.cs,源程序如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics.Contracts;
using System.Collections;

//参考微软 System.Collections.Generic.List<T> 链表类源代码
//https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646

namespace SequencedListDemo
{
    /// <summary>
    /// 线性表的顺序表存储:
    /// 方便查询,不方便频繁的插入和删除操作
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SequencedList<T> : IEnumerable<T>
    {
        /// <summary>
        /// 定义一个数组,用于存储和扩展线性顺序表
        /// </summary>
        private T[] items;
        /// <summary>
        /// 集合的当前元素个数
        /// </summary>
        private int count = 0;
        /// <summary>
        /// 表示一个空数组,集合元素个数为0,并不是null
        /// </summary>
        static readonly T[] emptyArray = new T[0];

        #region 构造函数
        /// <summary>
        /// 定义指定容量的顺序表
        /// </summary>
        /// <param name="capacity"></param>
        public SequencedList(int capacity)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException("容量不能为负数");
            }
            Contract.EndContractBlock();
            items = new T[capacity];
            count = capacity;
        }

        /// <summary>
        /// 默认空顺序表
        /// </summary>
        public SequencedList()
        {
            items = emptyArray;
        }

        /// <summary>
        /// 以初始化数组加载顺序表
        /// </summary>
        /// <param name="itemArray"></param>
        public SequencedList(T[] itemArray)
        {
            if (itemArray == null)
                throw new ArgumentNullException("参数数组不能为空");
            Contract.EndContractBlock();
            count = itemArray.Length;
            items = new T[count];
            Array.Copy(itemArray, items, itemArray.Length);
        }
        #endregion

        #region 属性与索引器
        /// <summary>
        /// 获取或设置容量大小
        /// </summary>
        public int Capacity
        {
            get
            {
                Contract.Ensures(Contract.Result<int>() >= 0);
                return items.Length;
            }
            set
            {
                if (value < count)
                    throw new ArgumentOutOfRangeException("参数越界异常");
                Contract.EndContractBlock();
                if (value != items.Length)
                {
                    if (value > 0)
                    {
                        T[] newItems = new T[value];
                        if (count > 0)
                        {
                            Array.Copy(items, 0, newItems, 0, count);
                        }
                        items = newItems;
                    }
                    else
                    {
                        items = emptyArray;
                    }
                }
            }
        }

        /// <summary>
        /// 获取当前集合的元素个数
        /// </summary>
        public int Count
        {
            get
            {
                Contract.Ensures(Contract.Result<int>() >= 0);
                return count;
            }
        }

        /// <summary>
        /// 集合是否为空
        /// </summary>
        public bool IsEmpty 
        {
            get 
            {
                return count == 0;
            }
        }

        /// <summary>
        /// 索引器:获取或设置指定索引的元素
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                if (index < 0 || index >= count)
                {
                    throw new ArgumentOutOfRangeException("索引非法,必须是0~count之间");
                }
                Contract.EndContractBlock();
                return items[index];
            }
            set
            {
                if (index < 0 || index >= count)
                {
                    throw new ArgumentOutOfRangeException("索引非法,必须是0~count之间");
                }
                Contract.EndContractBlock();
                items[index] = value;
            }
        }
        #endregion

        #region 添加或者插入元素
        /// <summary>
        /// 将一个元素添加到集合尾部,集合总个数加1。
        /// 如果需要,在添加新元素之前,列表的容量将增加一倍。
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            if (count >= items.Length) 
            {
                EnsureCapacity(count + 1);
            }
            items[count] = item;
            count++;
        }

        /// <summary>
        /// 将给定集合的元素添加到此集合的末尾。
        /// 如果需要,列表的容量将增加到以前容量或新大小的两倍,以较大者为准。 
        /// </summary>
        /// <param name="itemArray"></param>
        public void AddRange(T[] itemArray)
        {
            InsertRange(count, itemArray);
        }

        /// <summary>
        /// 在指定索引处插入一个元素
        /// </summary>
        /// <param name="index"></param>
        /// <param name="item"></param>
        public void Insert(int index, T item)
        {
            if (index < 0 || index > count) 
            {
                throw new ArgumentOutOfRangeException("索引非法,必须是0~count之间");
            }
            Contract.EndContractBlock();
            if (count >= items.Length)
            {
                EnsureCapacity(count + 1);
            }
            if (index < count)
            {
                //将数组的元素向后面移动一个索引
                Array.Copy(items, index, items, index + 1, count - index);
            }
            items[index] = item;
            count++;
        }

        /// <summary>
        /// 在指定的索引处插入一个数组
        /// </summary>
        /// <param name="index"></param>
        /// <param name="itemArray"></param>
        public void InsertRange(int index, T[] itemArray)
        {
            if (items == null) 
            {
                throw new ArgumentNullException("参数数组不能为null");
            }
            if (index < 0 || index > count)
            {
                throw new ArgumentOutOfRangeException("索引非法,必须是0~count之间");
            }
            Contract.EndContractBlock();
            //不考虑元素为0的情况
            if (itemArray.Length == 0) 
            {
                return;
            }
            EnsureCapacity(itemArray.Length + count);
            if (index < count)
            {
                Array.Copy(items, index, items, index + itemArray.Length, count - index);
            }
            T[] itemsToInsert = new T[itemArray.Length];
            itemArray.CopyTo(itemsToInsert, 0);
            itemsToInsert.CopyTo(items, index);

            count += itemArray.Length;
        }
        #endregion

        /// <summary>
        /// 确保容量:关键扩充逻辑
        /// 确保此列表的容量至少为给定的最小值。
        /// 如果列表的当前容量小于min,则容量增加到当前容量的两倍或最小,以较大者为准。
        /// </summary>
        /// <param name="min"></param>
        private void EnsureCapacity(int min)
        {
            if (items.Length < min)
            {
                int newCapacity = items.Length == 0 ? 4 : items.Length * 2;
                // 在遇到溢出之前,允许列表增长到可能的最大容量(~4M=4096*1024个元素).
                if ((uint)newCapacity > 0X400000)
                    newCapacity = 0X400000;
                if (newCapacity < min) 
                    newCapacity = min;

                //【Capacity的set访问器】:为属性赋值,如果容量不足时,为items数组两倍扩充,被复制元素到扩充后的新数组中
                Capacity = newCapacity;
            }
        }

        #region 移除指定或满足条件的元素

        /// <summary>
        /// 清除第一个匹配的元素,如果存在,则清除并返回true。不存在该元素则返回false
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Remove(T item)
        {
            //找出第一个符合的元素
            int index = IndexOf(item);
            if (index >= 0)
            {
                RemoveAt(index);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 清除指定索引处的元素
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= count) 
            {
                throw new ArgumentOutOfRangeException("索引非法,必须是0~count之间");
            }
            Contract.EndContractBlock();
            count--;
            if (index < count)
            {
                Array.Copy(items, index + 1, items, index, count - index);
            }
            items[count] = default(T);
        }

        /// <summary>
        /// This method removes all items which matches the predicate.
        /// The complexity is O(n). 
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public int RemoveAll(Predicate<T> match)
        {
            if (match == null)
            {
                throw new ArgumentNullException("匹配的委托不能为null");
            }
            Contract.Ensures(Contract.Result<int>() >= 0);
            Contract.Ensures(Contract.Result<int>() <= Contract.OldValue(Count));
            Contract.EndContractBlock();

            int freeIndex = 0;   // the first free slot in items array

            // Find the first item which needs to be removed.
            while (freeIndex < count && !match(items[freeIndex])) 
                freeIndex++;
            if (freeIndex >= count)
                return 0;

            int current = freeIndex + 1;
            while (current < count)
            {
                // Find the first item which needs to be kept.
                while (current < count && match(items[current])) 
                    current++;

                if (current < count)
                {
                    // copy item to the free slot.
                    items[freeIndex++] = items[current++];
                }
            }

            Array.Clear(items, freeIndex, count - freeIndex);
            int result = count - freeIndex;
            count = freeIndex;
            return result;
        }

        /// <summary>
        /// 清除集合中的所有元素
        /// </summary>
        public void Clear() 
        {
            if (count > 0)
            {
                Array.Clear(items, 0, count);
                count = 0;
            }
        }
        #endregion

        #region 包含与查找

        /// <summary>
        /// 集合是否包含某元素
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(T item)
        {
            if ((object)item == null) 
            {
                for (int i = 0; i < count; i++)
                {
                    if ((object)items[i] == null) 
                    {
                        return true;
                    }
                }
                return false;
            }

            //如果不为null
            for (int i = 0; i < count; i++)
            {
                if (item.Equals(items[i])) 
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 集合中是否存在指定条件的元素
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public bool Exists(Predicate<T> match)
        {
            return FindIndex(match) != -1;
        }

        /// <summary>
        /// 查找第一个符合指定条件的元素的索引,如果不存在,返回-1
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public int FindIndex(Predicate<T> match)
        {
            if (match == null)
                throw new ArgumentNullException("匹配条件不能为null");
            Contract.Ensures(Contract.Result<int>() >= -1 && Contract.Result<int>() < count);
            Contract.EndContractBlock();
            for (int i = 0; i < count; i++)
            {
                if (match(items[i])) 
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// 将所有指定条件的元素插入到集合中
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public SequencedList<T> FindAll(Predicate<T> match)
        {
            if (match == null)
                throw new ArgumentNullException("匹配条件不能为null");
            Contract.EndContractBlock();
            SequencedList<T> list = new SequencedList<T>();
            for (int i = 0; i < count; i++)
            {
                if (match(items[i]))
                {
                    list.Add(items[i]);
                }
            }
            return list;
        }

        /// <summary>
        /// 查找第一个满足条件的元素并返回,如果没有找到,则返回T类型的默认值
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public T Find(Predicate<T> match) 
        {
            if (match == null)
                throw new ArgumentNullException("匹配条件不能为null");
            Contract.EndContractBlock();
            for (int i = 0; i < count; i++)
            {
                if (match(items[i]))
                {
                    return items[i];
                }
            }
            return default(T);
        }

        public int IndexOf(T item)
        {
            Contract.Ensures(Contract.Result<int>() >= -1 && Contract.Result<int>() < count);
            return Array.IndexOf(items, item, 0, count);
        }
        #endregion

        #region 遍历与显示所有有效元素
        /// <summary>
        /// 显示所有元素
        /// </summary>
        public void Show() 
        {
            for (int i = 0; i < count; i++)
            {
                Console.Write(items[i] + " ");
            }
            Console.WriteLine();
        }

        /// <summary>
        /// 使用foreach必须实现接口IEnumerator的GetEnumerator()方法
        /// </summary>
        /// <returns></returns>
        public IEnumerator<T> GetEnumerator()
        {
            for (int i = 0; i < count; i++)
            {
                yield return items[i];
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }
}

在默认的 Program.cs输入如下测试代码:

using System;

namespace SequencedListDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            SequencedList<int> sequencedList = new SequencedList<int>(new int[] { 2, 3 });
            Console.WriteLine("---测试插入元素---");
            sequencedList.Insert(0, 1);
            sequencedList.Show();
            sequencedList.InsertRange(3, new int[] { 4, 5, 6 });
            sequencedList.Add(7);
            Console.WriteLine("---测试foreach遍历元素,必须实现接口IEnumerator的GetEnumerator()方法---");
            foreach (int item in sequencedList)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();

            int index = sequencedList.IndexOf(4);
            Console.WriteLine($"元素所在的索引:{index}");
            Console.WriteLine("---测试移除指定条件的元素---");
            sequencedList.RemoveAll(element => element < 3);
            sequencedList.Show();
            Console.WriteLine("---测试查找指定条件的所有元素---");
            SequencedList<int> listFind = sequencedList.FindAll(element => element.CompareTo(5) >= 0);
            listFind.Show();
            Console.ReadLine();
        }
    }
}

测试效果如图:

 

 

Guess you like

Origin blog.csdn.net/ylq1045/article/details/112796890