C#数据结构和算法

203 阅读2分钟

一、数组

image.png

实现数组的增加元素、删除指定下标元素、删除指定元素、查询对应元素下标,修改元素

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 数组
{
    internal class Array01
    {
        private int[] data;//数组
        private int N; //数组元素的个数

        public Array01(int capacity)
        {
            Console.WriteLine(capacity);
            data = new int[capacity];
            N = 0;
        }

        //无参构造方法
        public Array01() : this(10) {

            Console.WriteLine("2222");
        }

        public int Capaticy
        {
            get
            {
                return data.Length;
            }
        }
        public int Count
        {
            get { return N; }
        }

        public bool isEmpty
        {
            get { return N == 0; }
        }

        //往数组中,中间任意位置插入元素
        /// <summary>
        /// 
        /// </summary>
        /// <param name="index">需要插入哪个位置的下标</param>
        /// <param name="e">当前需要插入的值</param>
        public void Add(int index,int e)
        {
            if (index < 0 || index > N) throw new ArgumentException("数组索引越界");
            if (index == data.Length) ResetCapaticy(data.Length*2);
            //每插入一个元素,都是从最后一个元素的位置开始移动一个单位长度,并且长度+1
            for(int  i = N-1; i >=index; i--) { 
                //把前一个位置的值赋值给后一个位置
                data[i+1] = data[i];
            }
            //将新的元素赋值给当前需要插入元素的下标
            data[index] = e;
            N++;
        }

        //数组头部开始插入元素
        public void AddFirst(int e)
        {
            Add(0, e);
        }
        //数组的尾部插入元素
        public void AddLast(int e)
        {
            Add(N, e);
        }

        //查询的方法
        public int Get(int index)
        {
            if (index < 0 || index >= N)
                throw new AggregateException("数组越界");
            return data[index];
        }
        public int GetFirst()
        {
            return Get(0);
        }
        public int GetLast()
        {
            return Get(N - 1);
        }
        //修改
        public void Set(int index,int newIndex)
        {
            if (index < 0 || index >= N)
                throw new AggregateException("数组越界");
            data[index] = newIndex;
        }

        //是否包含某一个元素
        public bool Contains(int e)
        {
            for(int i = 0;i< N; i++)
            {
                if (data[i] == e) return true;
            }
            return false;
        }

        //返回对应数组元素下标
        public int IndexOf(int e)
        {
            for(int i = 0; i < N; i++)
            {
                if (data[i] == e) return i;
            }
            return -1;
        }

        //删除指定下标元素
        public int RemoveAt(int index)
        {
            if (index < 0 || index >= N)
                throw new AggregateException("数组越界");
            int del = data[index];
            for(int i = index + 1; i < N; i++)
            {
                data[i-1] = data[i];
            }
            N--;
            data[N] = default(int);
            if (N == data.Length / 4)
            {
                ResetCapaticy(data.Length / 2);
            }
            return del;
        }
        //删除数组开头元素
        public int RemoveFirst()
        {
            return RemoveAt(0);
        }
        //删除数组最后的元素
        public int RemoveLast()
        {
            return RemoveAt(N - 1);
        }

        //删除指定数据的元素
        public void Remove(int e)
        {
            int del = IndexOf(e);
            //Console.WriteLine(del);
            if (del != -1)
            {

                RemoveAt(del);
                Console.WriteLine("删除成功!");
            }
            else
            {
                throw new AggregateException("当前元素不在数组中,删除失败!");
            }
        }
        //数组的扩容
        private void ResetCapaticy(int newCapacity)
        {
            int[] newData = new int[newCapacity];
            for(int i = 0; i < N; i++)
            {
                newData[i] = data[i];
            }
            data = newData;
        }

        //重写tostring方法
        public override string ToString()
        {
            StringBuilder res = new StringBuilder();
            //格式化
            res.Append(string.Format("Array01: count={0} capacity={1}\n", N, data.Length));
            res.Append('[');
            for(int i = 0;i< N; i++)
            {
                res.Append(data[i]);
                if(i!=N-1) res.Append(',');
            }
            res.Append("]");
            return res.ToString();
        }
    }
}

main方法调用:

    using System.Collections;

namespace 数组
{
    internal class Program
    {
        static void Main(string[] args)
        {
            /*//静态数组,数组长度不能动态扩充
            int[] arr = new int[10];

            //动态数组ArrayList,长度可以根据插入的元素个数动态扩充,可以插入多种不同的数据类型到ArrayList中
            ArrayList arrayList = new ArrayList(10);
            for(int i =  0; i < 15; i++)
            {
                arrayList.Add(i);
            }
            foreach(int i in arrayList) Console.Write(i+" ");
            Console.WriteLine();
            //动态数组List,长度可以根据插入的元素个数动态扩充,但是list需要指定数据类型
            List<int> list = new List<int>(10);
            for (int i = 0; i < 15; i++)
            {
                list.Add(i);
            }
            foreach (int i in list) Console.Write(i + " ");
            Console.ReadLine();*/

            Array01 a = new Array01(20);
            //循环插入值
            for(int i = 0;i<10; i++)
            {
                a.AddLast(i);
            }
            Console.Write(a.ToString());
            Console.WriteLine();
            //中间插入值:
            a.Add(2, 100);
            Console.Write(a.ToString());
            Console.WriteLine();
            //头部插入
            a.AddFirst(50);
            Console.Write(a.ToString());
            Console.WriteLine();
            //修改某一个元素值
            a.Set(a.Count - 1, 99);
            Console.Write(a.ToString());
            Console.WriteLine();

            Console.WriteLine("--------------------------------");
            //删除下标位置元素
            a.RemoveLast();
            Console.Write(a.ToString());
            Console.WriteLine();

            a.RemoveFirst();
            Console.Write(a.ToString());
            Console.WriteLine();

            a.Remove(100);
            Console.Write(a.ToString());
            Console.WriteLine();


            Console.WriteLine("--------------------------------");
            a.AddLast(50);
            a.AddLast(70);
            Console.Write(a.ToString());
            Console.WriteLine();

            for(int i = 0; i < 6; i++)
            {
                a.RemoveLast();
            }
            Console.Write(a.ToString());
            Console.WriteLine();
        }
    }
}

最终结果:

image.png

二、装箱、拆箱

image.png

装箱拆箱只发生在ArrayList集合中,因为ArrayList底层是采用的object类型去存储元素,任何类型都能存储进去,这时候安全性不强。在开发中,强烈使用List进行开发

image.png

性能对比:

    //装箱和拆箱对比
            Console.WriteLine("测试值类型对象int");
            int n = 1000000;
            Stopwatch t1 = new Stopwatch();
            Stopwatch t2 = new Stopwatch();
            Stopwatch t3 = new Stopwatch();
            Stopwatch t4 = new Stopwatch();
            t1.Start();
            List<int> list1 = new List<int>();
            for(int i = 0; i < n; i++) { 
            
                list1.Add(i);//不发生装箱
                int x = list1[i]; //不发生拆箱
            }
            t1.Stop();
            Console.WriteLine("List Time:"+t1.ElapsedMilliseconds+"ms");


            t2.Start();
            ArrayList array1 = new ArrayList();
            for (int i = 0; i < n; i++)
            {

                array1.Add(i);//发生装箱--值类型转化为引用类型了,因为由最初的int装箱到object类型中
                int x = (int)array1[i]; //发生拆箱,由引用类型转化为值类型
            }
            t2.Stop();
            Console.WriteLine("ArrayList Time:" + t2.ElapsedMilliseconds + "ms");

            Console.WriteLine("测试引用类型对象string");

            t3.Start();
            List<string> list2 = new List<string>();
            for (int i = 0; i < n; i++)
            {

                list2.Add("X");//不发生装箱
                string x = list2[i]; //不发生拆箱
            }
            t1.Stop();
            Console.WriteLine("List Time:" + t3.ElapsedMilliseconds + "ms");


            t4.Start();
            ArrayList array2 = new ArrayList();
            for (int i = 0; i < n; i++)
            {

                array2.Add("X");//发生装箱--值类型转化为引用类型了,因为由最初的int装箱到object类型中
                string x = (string)array2[i]; //发生拆箱,由引用类型转化为值类型
            }
            t2.Stop();
            Console.WriteLine("ArrayList Time:" + t4.ElapsedMilliseconds + "ms");

            Console.Read();

性能对比图:

image.png

总结:相对于值类型存储,一定要使用List集合来进行存储,能很大程度的提高数据安全性以及内存性能,针对于引用类型,值类型和引用类型性能消耗不大,综上所述,推荐使用List很有必要!