数据结构之动态数组

1.静态数组是不可以更改数组长度的

2.动态数据组:ArrayList,List(泛型)。动态数组本质上就是数组,是由静态数组封装的一些扩容能力。

下面看一下动态数组的底层实现原理,并创建属于自己的动态数组,

复制代码
  public class MyArray
    {
        //设置私有,防止用户私自查看更改。
        private int[] data;
        //表示此数组目前数组实际存储元素数量
        private int N;


        #region  设置外部可以查看数组信息的属性方法

        /// <summary>
        /// 在这里构造整个数组的长度
        /// </summary>
        /// <param name="capacity"></param>
        public MyArray(int capacity)
        {
            data = new int[capacity];
            N = 0;
        }
        /// <summary>
        /// 因为目前要做动态数组,所以我们可以在无参构造函数这里
        /// 先默认一个长度,比如10。
        /// </summary>
        //public MyArray()
        //{
        //    data = new int[10];
        //    N = 0;
        //}

        //注意这个写法和上面注释的无参构造函数一样,
        //只不过是借用了有参构造函数,往里面传入了一个定死的值。
        public MyArray() : this(10)
        {
        }
        /// <summary>
        /// 数组长度
        /// </summary>
        public int Length
        {
            get
            {
                return data.Length;
            }
        }
        /// <summary>
        /// 数组实际存储数量
        /// </summary>
        public int Count
        {
            get
            {
                return N;
            }
        }
        /// <summary>
        /// 可以看数组元素是否为空
        /// </summary>
        public bool IsNull
        {
            get
            {
                return N == 0;
            }
        }
        #endregion


        #region 添加数组
        /// <summary>
        /// 添加方法
        /// </summary>
        /// <param name="index"></param>
        /// <param name="v"></param>
        public void Add(int index, int v)
        {
            //前提要看长度是否足够
            if (index < 0 || index > N)
            {
                throw new Exception("数组索引越界上");
            }
            if (N == data.Length)
            {
                throw new Exception("数组已满");
            }

            //首先要将index后面的值依次往后移动一位,防止值被覆盖
            for (int i = N - 1; i >= index; i--)
            {
                data[i + 1] = data[i];
            }

            //赋值
            data[index] = v;
            N++;//元素数量加一

        }
        /// <summary>
        /// 末尾添加
        /// </summary>
        /// <param name="v"></param>
        public void AddLast(int v)
        {
            Add(N, v);
        }
        /// <summary>
        /// 头部添加
        /// </summary>
        /// <param name="v"></param>
        public void AddFirst(int v)
        {
            Add(0, v);
        }

        #endregion

        #region 获取  修改  删除

        public int Get(int index)
        {
            //确认索引合法性
            if (index < 0 || index >= N)
            {
                throw new Exception("索引超出数组长度");
            }

            return data[index];
        }

        public int RemoveAt(int index)
        {
            if (index < 0 || index >= N)
            {
                throw new Exception("索引超出数组长度");
            }

            int del = data[index];
            //被删除当前元素的后面值依次向前回退一步
            for (int i = index - 1; i <= N - 1; i++)
            {
                data[i - 1] = data[i];
            }

            N--;
            //给最高位默认值,因为此时还未实现数组的缩容,暂时这样处理
            data[N] = default(int);
            return del;
        }
        /// <summary>
        /// 重写tosting,按照指定的方式输出
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            //按照自己的喜好重写
            return "";
        }

        #endregion
    }
复制代码

下面实现自定义数组的扩容,缩容功能  下面在增加元素和删除元素的时候都自动进行判断是否需要进行扩容和缩容

复制代码
    public class MyArray
    {
        //设置私有,防止用户私自查看更改。
        private int[] data;
        //表示此数组目前数组实际存储元素数量
        private int N;


        #region  设置外部可以查看数组信息的属性方法

        /// <summary>
        /// 在这里构造整个数组的长度
        /// </summary>
        /// <param name="capacity"></param>
        public MyArray(int capacity)
        {
            data = new int[capacity];
            N = 0;
        }
        /// <summary>
        /// 因为目前要做动态数组,所以我们可以在无参构造函数这里
        /// 先默认一个长度,比如10。
        /// </summary>
        //public MyArray()
        //{
        //    data = new int[10];
        //    N = 0;
        //}

        //注意这个写法和上面注释的无参构造函数一样,
        //只不过是借用了有参构造函数,往里面传入了一个定死的值。
        public MyArray() : this(10)
        {
        }
        /// <summary>
        /// 数组长度
        /// </summary>
        public int Length
        {
            get
            {
                return data.Length;
            }
        }
        /// <summary>
        /// 数组实际存储数量
        /// </summary>
        public int Count
        {
            get
            {
                return N;
            }
        }
        /// <summary>
        /// 可以看数组元素是否为空
        /// </summary>
        public bool IsNull
        {
            get
            {
                return N == 0;
            }
        }
        #endregion


        #region 添加数组
        /// <summary>
        /// 添加方法
        /// </summary>
        /// <param name="index"></param>
        /// <param name="v"></param>
        public void Add(int index, int v)
        {
            //前提要看长度是否足够
            if (index < 0 || index > N)
            {
                throw new Exception("数组索引越界上");
            }
            if (N == data.Length)
            {
                //扩大一倍
                ResetCapacity(N * 2);
                //  throw new Exception("数组已满");
            }

            //首先要将index后面的值依次往后移动一位,防止值被覆盖
            for (int i = N - 1; i >= index; i--)
            {
                data[i + 1] = data[i];
            }

            //赋值
            data[index] = v;
            N++;//元素数量加一

        }
        /// <summary>
        /// 末尾添加
        /// </summary>
        /// <param name="v"></param>
        public void AddLast(int v)
        {
            Add(N, v);
        }
        /// <summary>
        /// 头部添加
        /// </summary>
        /// <param name="v"></param>
        public void AddFirst(int v)
        {
            Add(0, v);
        }

        #endregion

        #region 获取  修改  删除

        public int Get(int index)
        {
            //确认索引合法性
            if (index < 0 || index >= N)
            {
                throw new Exception("索引超出数组长度");
            }

            return data[index];
        }

        public int RemoveAt(int index)
        {
            if (index < 0 || index >= N)
            {
                throw new Exception("索引超出数组长度");
            }
            //如果元素数量不足长度4分之一,进行缩容,减少空间使用。
            if (N != data.Length / 4)
            {
                //缩小一半
                ResetCapacity(data.Length / 2);
            }


            int del = data[index];
            //被删除当前元素的后面值依次向前回退一步
            for (int i = index - 1; i <= N - 1; i++)
            {
                data[i - 1] = data[i];
            }

            N--;
            //给最高位默认值,因为此时还未实现数组的缩容,暂时这样处理
            data[N] = default(int);
            return del;
        }
        /// <summary>
        /// 重写tosting,按照指定的方式输出
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            //按照自己的喜好重写
            return "";
        }

        #endregion

        #region 动态扩容 缩容

        private void ResetCapacity(int newLength)
        {
            int[] newData = new int[newLength];
            //将旧有数据复制到扩容后的新数组中
            data.CopyTo(newData, 0);
            //赋值给原有数组 注意此时给data的是引用,data中数据更改newData同样会变
            data = newData; 
        }


        #endregion


    }
复制代码

 

但是上面的代码只能int,所以用泛型实现多类型。类似List泛型类

复制代码
 public class MyArray<T>
    {
        //设置私有,防止用户私自查看更改。
        private T[] data;
        //表示此数组目前数组实际存储元素数量
        private int N;


        #region  设置外部可以查看数组信息的属性方法

        /// <summary>
        /// 在这里构造整个数组的长度
        /// </summary>
        /// <param name="capacity"></param>
        public MyArray(int capacity)
        {
            data = new T[capacity];
            N = 0;
        }
        /// <summary>
        /// 因为目前要做动态数组,所以我们可以在无参构造函数这里
        /// 先默认一个长度,比如10。
        /// </summary>
        //public MyArray()
        //{
        //    data = new int[10];
        //    N = 0;
        //}

        //注意这个写法和上面注释的无参构造函数一样,
        //只不过是借用了有参构造函数,往里面传入了一个定死的值。
        public MyArray() : this(10)
        {
        }
        /// <summary>
        /// 数组长度
        /// </summary>
        public int Length
        {
            get
            {
                return data.Length;
            }
        }
        /// <summary>
        /// 数组实际存储数量
        /// </summary>
        public int Count
        {
            get
            {
                return N;
            }
        }
        /// <summary>
        /// 可以看数组元素是否为空
        /// </summary>
        public bool IsNull
        {
            get
            {
                return N == 0;
            }
        }
        #endregion


        #region 添加数组
        /// <summary>
        /// 添加方法
        /// </summary>
        /// <param name="index"></param>
        /// <param name="v"></param>
        public void Add(int index, T v)
        {
            //前提要看长度是否足够
            if (index < 0 || index > N)
            {
                throw new Exception("数组索引越界上");
            }
            if (N == data.Length)
            {
                //扩大一倍
                ResetCapacity(N * 2);
                //  throw new Exception("数组已满");
            }

            //首先要将index后面的值依次往后移动一位,防止值被覆盖
            for (int i = N - 1; i >= index; i--)
            {
                data[i + 1] = data[i];
            }

            //赋值
            data[index] = v;
            N++;//元素数量加一

        }
        /// <summary>
        /// 末尾添加
        /// </summary>
        /// <param name="v"></param>
        public void AddLast(T v)
        {
            Add(N, v);
        }
        /// <summary>
        /// 头部添加
        /// </summary>
        /// <param name="v"></param>
        public void AddFirst(T v)
        {
            Add(0, v);
        }

        #endregion

        #region 获取  修改  删除

        public T Get(int index)
        {
            //确认索引合法性
            if (index < 0 || index >= N)
            {
                throw new Exception("索引超出数组长度");
            }

            return data[index];
        }

        public T RemoveAt(int index)
        {
            if (index < 0 || index >= N)
            {
                throw new Exception("索引超出数组长度");
            }
            //如果元素数量不足长度4分之一,进行缩容,减少空间使用。
            if (N != data.Length / 4)
            {
                //缩小一半
                ResetCapacity(data.Length / 2);
            }


            T del = data[index];
            //被删除当前元素的后面值依次向前回退一步
            for (int i = index - 1; i <= N - 1; i++)
            {
                data[i - 1] = data[i];
            }

            N--;
            //给最高位默认值,因为此时还未实现数组的缩容,暂时这样处理
            data[N] = default(T);
            return del;
        }
        /// <summary>
        /// 重写tosting,按照指定的方式输出
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            //按照自己的喜好重写
            return "";
        }

        #endregion

        #region 动态扩容 缩容

        private void ResetCapacity(int newLength)
        {
            T[] newData = new T[newLength];
            //将旧有数据复制到扩容后的新数组中
            data.CopyTo(newData, 0);
            //赋值给原有数组 注意此时给data的是引用,data中数据更改newData同样会变
            data = newData; 
        }


        #endregion


    }
复制代码

 

posted @   安静点--  阅读(406)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示