2.ArrayList

2.简单数据结构类-ArrayList


2.1 知识点

练习题回顾

C#核心中索引器的练习题

自定义一个整形数组类,该类中有一个整形数组变量,为它封装增删查改的方法。

ArrayList的本质

ArrayList是一个C#为我们封装好的类,它的本质是一个object类型的数组(可以存储任何类型的数组)。ArrayList类帮助我们实现了很多方法,比如数组的增删查改。

ArrayList的申明

需要引用命名空间using System.Collections; 包含一些集合类。

ArrayList arrayList = new ArrayList();

ArrayList的增删查改和遍历

当前arrayList中的元素有:

{}

Add方法:直接在ArrayList末尾增加对应元素。

arrayList.Add(1);
arrayList.Add("123");
arrayList.Add(true);
arrayList.Add(new object());
arrayList.Add(new Test());
arrayList.Add(1);
arrayList.Add(true);

AddRange方法:范围增加(批量增加,把另一个ArrayList容器里面的所有元素加到当前ArrayList容器后面)。

ArrayList arrayList2 = new ArrayList();
arrayList2.Add("我是arrayList2中的元素");
arrayList.AddRange(arrayList2); // 会把arrayList2中所有元素拼接在arrayList后面

Insert方法:往指定位置插入元素。

arrayList.Insert(8, "我是arrayList中索引为8的元素");
Console.WriteLine(arrayList[8]); // 我是arrayList中索引为8的元素

增完之后arrayList中的元素有:

{ 1, 123, True, System.Object, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

当前arrayList中的元素有:

{ 1, 123, True, System.Object, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

Remove方法:移除指定元素,从头找,找到即删,假如有多个只会删除第一个。

arrayList.Remove(1); // 删除指定元素1

RemoveAt方法:移除指定位置的元素,索引从0开始。

arrayList.RemoveAt(2); // 删除索引为2的System.Object

Clear方法:清空ArrayList中所有元素。

// arrayList.Clear(); // 为了后面测试方便,先注释

删完之后arrayList中的元素有:

{ 123, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

当前arrayList中的元素有:

{ 123, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

ArrayList[x]索引器get:得到指定位置x的元素。

Console.WriteLine(arrayList[0]); // 123

Contains方法:传入元素,查看元素是否存在。存在返回true,否则返回false

if (arrayList.Contains("123"))
{
    Console.WriteLine("存在123"); // 存在123
}

IndexOf方法:正向查找元素位置。

// 找到的返回值是位置,找不到返回值是-1,假如有多个,只会返回从头数第一找到的元素的位置
int index = arrayList.IndexOf(true);
Console.WriteLine(index); // 1 找到从头数第一个true在索引1位置,假如有两个true只会返回第一个true所在的位置
Console.WriteLine(arrayList.IndexOf(false)); // -1 找不到false这个元素

LastIndexOf方法:反向查找元素位置。

// 返回时从头开始的索引数
index = arrayList.LastIndexOf(true);
Console.WriteLine(index); // 4 找到从末尾数第一个true在索引4位置,假如有两个true只会返回从末尾数第一个true所在的位置

当前arrayList中的元素有:

{ 123, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

ArrayList[x] = “”索引器set:修改指定位置x的元素。

Console.WriteLine(arrayList[0]); // 123
arrayList[0] = "999";
Console.WriteLine(arrayList[0]); // 999

改完之后arrayList中的元素有:

{ 999, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

遍历

当前arrayList中的元素有:

{ 999, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }

Count属性:返回ArrayList的长度,具体存了多少个。

Console.WriteLine(arrayList.Count); // 7

Capacity属性:返回ArrayList的容量。

// 每次长度大于容量时会扩容至当前容量的两倍,避免产生过多的垃圾
Console.WriteLine(arrayList.Capacity); // 16

普通for循环遍历:

Console.WriteLine("**********普通for循环遍历**********");
for (int i =

 0; i < arrayList.Count; i++)
{
    Console.WriteLine(arrayList[i]);
    //{ 999, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }
}

迭代器foreach遍历:

Console.WriteLine("**********迭代器foreach遍历**********");
foreach (object item in arrayList)
{
    Console.WriteLine(item);
    //{ 999, True, Lesson01_ArrayList.Test, 1, True, 我是arrayList2中的元素, 我是arrayList中索引为8的元素 }
}

ArrayList的装箱拆箱

ArrayList本质上是一个可以自动扩容的object数组,由于用object来存储数据,自然存在装箱拆箱。当往其中进行值类型存储时就是在装箱,当将值类型元素取出来转换使用时,就存在拆箱。

实例:

int k = 1;
arrayList[0] = k; // 装箱,ArrayList的元素是object类型的,把值类型用引用类型来存 
k = (int)arrayList[0]; // 拆箱,ArrayList的元素是object类型的,把引用类型强转成值类型

2.2 知识点代码

using System;
using System.Collections;

namespace Lesson01_ArrayList
{
    class Test
    {

    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("ArrayList");

            #region 练习题回顾
            //C#核心中  索引器的练习题
            //自定义一个整形数组类,该类中有一个整形数组变量,为它封装增删查改的方法
            #endregion

            #region 知识点一 ArrayList的本质
            //ArrayList是一个C#为我们封装好的类,
            //它的本质是一个object类型的数组(可以存储任何类型的数组),
            //ArrayList类帮助我们实现了很多方法,
            //比如数组的增删查改
            #endregion

            //主函数内

            #region 知识点二 ArrayList的申明
            //需要引用命名空间using System.Collections; 包含一些集合类
            ArrayList arrayList = new ArrayList();
            #endregion

            #region 知识点三 ArrayList的增删查改和遍历

            #region 增

            //当前arrayList中的元素有
            //{}

            //Add方法 直接在ArrayList末尾增加对应元素
            arrayList.Add(1);
            arrayList.Add("123");
            arrayList.Add(true);
            arrayList.Add(new object());
            arrayList.Add(new Test());
            arrayList.Add(1);
            arrayList.Add(true);

            //AddRange方法 范围增加(批量增加 把另一个ArrayList容器里面的所有元素加到当前ArrayList容器后面)
            ArrayList arrayList2 = new ArrayList();
            arrayList2.Add("我是arrayList2中的元素");
            arrayList.AddRange(arrayList2);//会把arrayList2中所有元素拼接在arrayList后面

            //Insert方法 往指定位置插入元素
            arrayList.Insert(8, "我是arrayList中索引为8的元素");
            Console.WriteLine(arrayList[8]);//我是arrayList中索引为8的元素

            //增完之后arrayList中的元素有
            //{ 1,123,True,System.Object,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            #endregion

            #region 删

            //当前arrayList中的元素有
            //{ 1,123,True,System.Object,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            //Remove方法 移除指定元素 从头找 找到删 假如有多个只会删除第一个
            arrayList.Remove(1);//删除指定元素1

            //RemoveAt方法 移除指定位置的元素 索引从0开始
            arrayList.RemoveAt(2);//删除索引为2的System.Object

            //Clear方法 清空ArrayList中所有元素
            //arrayList.Clear();//为了后面测试方便 先注释

            //删完之后arrayList中的元素有
            //{123,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            #endregion

            #region 查

            //当前arrayList中的元素有
            //{123,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            //ArrayList[x] 得到指定位置x的元素
            Console.WriteLine(arrayList[0]);//123

            //Contains方法 传入元素 查看元素是否存在 存在返回true 否则返回false
            if ( arrayList.Contains("123") )
            {
                Console.WriteLine("存在123");//存在123
            }

            //IndexOf方法 正向查找元素位置
            //找到的返回值是位置 找不到返回值是-1
            //假如有多个 只会返回从头数第一找到的元素的位置

            //之前往arrayList添加过 true 这个元素 找得到
            int index = arrayList.IndexOf(true);
            Console.WriteLine(index);//1 找到从头数第一个ture在索引1位置 假如有两个ture只会返回第一个true所在的位置
            Console.WriteLine(arrayList.IndexOf(false));//-1 找不到false这个元素

            //LastIndexOf方法 反向查找元素位置
            //返回时从头开始的索引数
            index = arrayList.LastIndexOf(true);
            Console.WriteLine(index);//4 找到从末尾数第一个ture在索引4位置 假如有两个ture只会返回从末尾数第一个true所在的位置

            #endregion

            #region 改

            //当前arrayList中的元素有
            //{123,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            //ArrayList[x] = "" 修改指定位置x的元素
            Console.WriteLine(arrayList[0]);//123
            arrayList[0] = "999";
            Console.WriteLine(arrayList[0]);//999

            //改完之后arrayList中的元素有
            //{999,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            #endregion

            #region 遍历

            //当前arrayList中的元素有
            //{999,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}

            //Count属性 返回ArrayList的长度 具体存了多少个
            Console.WriteLine(arrayList.Count);//7

            //Capacity属性 返回ArrayList的容量
            //每次长度大于容量时会扩容至当前容量的两倍 避免产生过多的垃圾
            Console.WriteLine(arrayList.Capacity);//16

            //普通for循环遍历
            Console.WriteLine("**********普通for循环遍历**********");
            for (int i = 0; i < arrayList.Count; i++)
            {
                Console.WriteLine(arrayList[i]);
                //{999,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}
            }

            //迭代器foreach遍历
            Console.WriteLine("**********迭代器foreach遍历**********");
            foreach (object item in arrayList)
            {
                Console.WriteLine(item);
                //{999,True,Lesson01_ArrayList.Test,1,True,我是arrayList2中的元素,我是arrayList中索引为8的元素}
            }

            #endregion

            #endregion

            #region 知识点四 ArrayList的装箱拆箱

            //ArrayList本质上是一个可以自动扩容的object数组,
            //由于用万物之父来存储数据,自然存在装箱拆箱。
            //当往其中进行值类型存储时就是在装箱,当将值类型元素取出来转换使用时,就存在拆箱。
            //所以ArrayList尽量少用,之后我们会学习更好的数据容器。

            //实例
            int k = 1;
            arrayList[0] = k;//装箱 arrayList的元素是object类型的 把值类型用引用类型来存 
            k = (int)arrayList[0];//拆箱 arrayList的元素是object类型的 把引用类型强转成值类型

            #endregion
        }
    }
}

2.3 练习题

请简述ArrayList和数组的区别

  • ArrayList本质上是一个object数组的封装,而数组是一种数据结构,用来存储固定大小的相同类型元素的集合。
  • ArrayList可以动态增长和缩减,而数组的长度在创建时就已经确定,不能动态改变。
  • 数组可以指定存储类型,而ArrayList默认存储的是object类型。
  • 数组的增删操作需要手动实现,而ArrayList提供了方便的API来实现增删操作。
  • 使用ArrayList时可能存在装箱拆箱的问题,而数组不会存在这个问题,除非是object数组。
  • 数组的长度属性为Length,而ArrayList的长度属性为Count。

创建一个背包管理类,使用ArrayList存储物品,实现购买物品,卖出物品,显示物品的功能。购买与卖出物品会导致金钱变化

class语句块外 namespace语句块内

// 背包管理类
class BagMgr
{
    // 背包中的物品列表
    private ArrayList items;

    // 背包中的金钱
    private int money;

    // 背包管理类构造函数,初始化背包中的金钱和物品列表
    public BagMgr(int money)
    {
        this.money = money;
        items = new ArrayList();
    }

    // 购买物品
    public void BuyItem(Item item)
    {
        // 检测物品信息是否正确
        if (item.num <= 0 || item.money < 0)
        {
            Console.WriteLine("请传入正确的物品信息");
            return;
        }

        // 检查金钱是否足够
        if (this.money < item.money * item.num)
        {
            Console.WriteLine("买不起,钱不够");
            return;
        }

        // 扣除金钱
        this.money -= item.money * item.num;
        Console.WriteLine("购买{0}{1}个,花费{2}钱", item.name, item.num, item.money * item.num);
        Console.WriteLine("剩余{0}元钱");

        // 检查背包中是否已有该物品,如有,数量叠加
        foreach (Item i in items)
        {
            if (i.id == item.id)
            {
                i.num += item.num;
                return;
            }
        }

        // 若背包中没有该物品,则添加到背包
        items.Add(item);
    }

    // 卖出物品
    public void SellItem(Item item)
    {
        for (int i = 0; i < items.Count; i++)
        {
            if ((items[i] as Item).id == item.id)
            {
                int num = Math.Min((items[i] as Item).num, item.num); // 实际卖出的数量
                string name = (items[i] as Item).name;
                int sellMoney = (int)(num * (items[i] as Item).money * 0.8f); // 打八折
                this.money += sellMoney; // 加到总金币中

                Console.WriteLine("卖了{0}{1}个,赚了{2}钱", name, num, sellMoney);
                Console.WriteLine("目前拥有{0}元钱", this.money);

                // 减少背包中物品数量,如果数量为0,则从背包中移除该物品
                (items[i] as Item).num -= num;
                if ((items[i] as Item).num == 0)
                {
                    items.RemoveAt(i);
                }
                return;
            }
        }
    }

    // 显示物品
    public void ShowItem()
    {
        foreach (Item item in items)
        {
            Console.WriteLine("有{0}{1}个", item.name, item.num);
        }
        Console.WriteLine("当前拥有{0}元钱", this.money);
    }
}

// 物品类
class Item
{
    public int id; // 物品唯一ID
    public int money; // 物品价格
    public string name; // 物品名称
    public int num; // 物品数量

    // 物品类构造函数
    public Item(int id, int money, string name, int num)
    {
        this.id = id;
        this.money = money;
        this.name = name;
        this.num = num;
    }
}

主函数内

BagMgr myBag = new BagMgr(99999); // 初始化背包,金钱99999

// 创造几个物品
Item item1 = new Item(1, 10, "红药", 10);
Item item2 = new Item(2, 20, "蓝药", 10);
Item item3 = new Item(3, 999, "屠龙刀", 1);

myBag.BuyItem(item1); // 购买红药10个,花费100钱,剩余99899元钱
myBag.BuyItem(item2); // 购买蓝药10个,花费200钱,剩余99699元钱
myBag.BuyItem(item3); // 购买屠龙刀1个,花费999钱,剩余98700元钱

myBag.SellItem(item3); // 卖了屠龙刀1个,赚了799钱,目前拥有99499元钱
myBag.SellItem(1, 1); // 卖了红药1个,

赚了8钱,目前拥有99507元钱
myBag.SellItem(1, 1); // 卖了红药1个,赚了8钱,目前拥有99515元钱
myBag.SellItem(2, 1); // 卖了蓝药1个,赚了16钱,目前拥有99531元钱
myBag.SellItem(2, 1); // 卖了蓝药1个,赚了16钱,目前拥有99547元钱

2.4 练习题代码

using System;
using System.Collections;

namespace Lesson01_练习题
{
    #region 练习题一
    //请简述ArrayList和数组的区别
    #region 答案
    //ArrayList本质上是一个object数组的封装

    //1.ArrayList可以不用一开始就定长,单独使用数组是定长的
    //2.数组可以指定存储类型,ArrayList默认为object类型
    //3.数组的增删需要我们自己去实现,ArrayList帮我们封装了方便的API来使用
    //4.ArrayList使用时可能存在装箱拆箱,数组使用时只要不是object数组那就不存在这个问题
    //5.数组长度为Length, ArrayList长度为Count
    #endregion
    #endregion

    //class语句块外 namespace语句块内

    #region 练习题二
    //创建一个背包管理类,使用ArrayList存储物品,
    //实现购买物品,卖出物品,显示物品的功能。购买与卖出物品会导致金钱变化

    //背包管理类
    class BagMgr
    {
        //背包中的物品列表
        private ArrayList items;

        //背包中有多少钱
        private int money;

        //背包管理类构造函数 初始化背包中有多少钱和背包中的物品列表
        public BagMgr( int money )
        {
            this.money = money;
            items = new ArrayList();
        }

        //购买物品 传入一个item
        public void BuyItem(Item item)
        {
            //检测传入的item中的信息是否正确
            if( item.num <= 0 || item.money < 0 )
            {
                Console.WriteLine("请传入正确的物品信息");
                return;
            }

            //检查钱够不够
            if( this.money < item.money*item.num )
            {
                //买不起 钱不够
                Console.WriteLine("买不起 钱不够");
                return;
            }

            //钱够的话 减钱
            this.money -= item.money * item.num;
            Console.WriteLine("购买{0}{1}个花费{2}钱", item.name, item.num, item.money * item.num);
            Console.WriteLine("剩余{0}元钱", this.money);

            //如果想要叠加物品 可以在前面先判断 是否有这个物品 然后加数量
            //只能遍历背包中的物品列表来判断
            for (int i = 0; i < items.Count; i++)
            {
                if( (items[i] as Item).id == item.id )
                {
                    //叠加数量
                    (items[i] as Item).num += item.num;
                    return;
                }
            }

            //如果走到这说明当前背包里没有这类item 把这一类物品加到背包中
            items.Add(item);
        }

        //卖出物品 传入一个item
        public void SellItem(Item item)
        {
            //遍历背包
            for (int i = 0; i < items.Count; i++)
            {
                //如何判断 卖的东西我背包里有没有?
                //我们要判断 卖的物品 我有没有 一般不这样判断
                //if(items[i] == item)
                //{

                //}
                //这其实是在比较 两个引用地址 指向的是不是同一个房间
                //或者说
                //比较的是 两个item在栈上存的指向堆中的值 想不想等 
                //不是传的new出来的同一个对象 肯定不相等的

                //通过id判断卖的东西我背包里有没有
                if ( (items[i] as Item).id == item.id )
                {
                    //创建临时变量方便记录
                    int num = 0;//实际卖了多少个item
                    string name = (items[i] as Item).name;//item名
                    int money = (items[i] as Item).money;//item单价

                    //卖东西的时候有两种情况

                    //1.假如要卖的东西比我身上的少 说明我有更多这个item 直接卖
                    if ((items[i] as Item).num > item.num)
                    {
                        //有更多这个item 直接赋值实际卖了多少个item
                        num = item.num;
                    }

                    //2.假如要卖的东西比我身上的多 说明我没有那么多这个item 只能卖我当前有多少个这个item 全部卖完
                    else
                    {
                        //实际卖了多少个item 就是 我拥有多少个这个item 
                        num = (items[i] as Item).num;

                        //卖完了 这个item就从背包上移除了
                        items.RemoveAt(i);
                    }

                    int sellMoney = (int)(num * money * 0.8f);//卖出去赚的总价 打八折
                    this.money += sellMoney;//加到总金币中

                    Console.WriteLine("卖了{0}{1}个,赚了{2}钱", name, num, sellMoney);
                    Console.WriteLine("目前拥有{0}元钱", this.money);

                    return;
                }
            }
        }

        //卖出物品 传入物品的id和数量
        public void SellItem(int id, int num = 1)
        {
            //直接调用上面写好的重载卖出物品方法 
            //直接构造一个Item类 把ID和数量两个关键信息设置了即可 就可以卖了
            Item item = new Item(id, num);
            SellItem(item);
        }

        //显示物品
        public void ShowItem()
        {
            //临时变量 用于遍历
            Item item;

            //遍历背包
            for (int i = 0; i < items.Count; i++)
            {
                //赋值临时变量 打印输出
                item = items[i] as Item;
                Console.WriteLine("有{0}{1}个", item.name, item.num);
            }

            Console.WriteLine("当前拥有{0}元钱", this.money);
        }
    }

    //物品类
    class Item
    {
        //物品唯一ID 来区分物品的种类
        public int id;

        //物品多少钱(单价)
        public int money;

        //物品名字
        public string name;

        //物品信息
        //public string tips;

        //物品数量
        public int num;

        //物品类构造函数
        public Item(int id, int num)
        {
            this.id = id;
            this.num = num;
        }
        public Item(int id, int money, string name, int num)
        {
            this.id = id;
            this.money = money;
            this.name = name;
            this.num = num;
        }
    }

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("ArrayList练习题");

            //主函数内

            #region 练习题二

            BagMgr myBag = new BagMgr(99999);//new出背包 初始化金币99999

            //创造几个物品
            Item item1 = new Item(1, 10, "红药", 10);
            Item item2 = new Item(2, 20, "蓝药", 10);
            Item item3 = new Item(3, 999, "屠龙刀", 1);

            myBag.BuyItem(item1);//购买红药10个花费100钱 剩余99899元钱
            myBag.BuyItem(item2);//购买蓝药10个花费200钱 剩余99699元钱
            myBag.BuyItem(item3);//购买屠龙刀1个花费999钱 剩余98700元钱

            myBag.SellItem(item3);//卖了屠龙刀1个,赚了799钱 目前拥有99499元钱
            myBag.SellItem(1, 1);//卖了红药1个,赚了8钱 目前拥有99507元钱
            myBag.SellItem(1, 1);//卖了红药1个,赚了8钱 目前拥有99515元钱
            myBag.SellItem(2, 1);//卖了蓝药1个,赚了16钱 目前拥有99531元钱
            myBag.SellItem(2, 1);//卖了蓝药1个,赚了16钱 目前拥有99547元钱

            #endregion
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏