数组(Array)
什么是数组?
是一个存储相同类型元素的固定大小的顺序集合。
有什么作用吗?
一次声明相同类型的数。
有哪些特点?
- 元素是相同类型
- 大小固定
- 元素连续存储
- 是引用类型(必须分配堆上的内存)
数组有哪些优点?
在内存中连续存储,因此可以快速而容易地从头到尾遍历元素,可以快速地修改元素
数组有哪些缺点呢?
- 创建时必须要指定数组变量的大小,在两个元素之间添加元素比较困难。
- 造成数组长度设置过大,内存空间浪费
- 数组长度过小,溢出
如何创建一个数组?
//第一种方式 int[] num1 = new int[10]; //长度为10,下标为0-9,int类型 //第二种方式 int[] num2 = new int[] { 1,2,3,4,5}; //此数组就存5个值 //第三种方式 int[] num3 = new int[3] { 1, 2, 3 }; //个数和声明数必须一致。此数组就存3个值,值都清楚 //第四种方式 int[] num4 = { 1, 2, 3, 4, 5 }; //简写法
怎么给数组赋值?
int[] num1 = new int[10]; //长度为10,下标为0-9,int类型 num1[8] = 20; //给8这个地方赋个值 Console.WriteLine(num1[8]); Console.ReadKey();
比方,盖一栋楼,一共有10层,有个开房的,它就去找6层房牌号为100的这个房间
如何遍历一个数组循环输出里面的内容
int[] nums = new int[5]; //声明一个数组 for (int i = 0; i < nums.Length; i++) //赋值 { nums[i] = 10; } for(int i = 0; i < nums.Length; i++) //取值 { Console.WriteLine(nums[i]); } Console.ReadKey();
如何在数组的两个元素之间添加元素?★★★
方法:使用泛型List<T>,先将元素存入List中,最后使用ToArray()转成数组。链接:C#中如何向数组中动态添加元素
第一步、将int数组转成List<int>
int[] num = new int[] { 1, 2, 3, 4 }; //定义一个int类型数组,长度为4 List<int> strList = new List<int>(num); //将int数组转成泛型List<int> strList.Add(5); //将要添加的元素存入泛型里面(这个方法默认是在结尾添加) strList.Insert(0, 9); //在指定索引处添加值
第二步、List<int>转int数组
int[] numm = strList.ToArray(); //将泛型转成数组 for (int i = 0; i < numm.Length; i++) //遍历数组元素 { Console.WriteLine(numm[i]); //输出数组的值 } Console.ReadKey(); //在控制台输出结果
如何解决数组的这些问题呢?
.NET Framework提供了用于数据存储和检索的专用类,这些类统称集合。这些类提供对堆栈、队列、列表和哈希表的支持。大多数集合类实现相同的接口。来克服这些缺点
集合(ArrayList)
是什么?
动态数组。有序集合
有什么特点?
- 初始容量为0
- 不用限定长度
- 集合可以使用索引在指定的位置添加和移除项目,动态数组会自动调整它的大小
- 在列表中进行动态内存分配、增加、搜索、排序各项
- 集合的变量影响全局,始终保证元素的连续性
集合ArrayList相比数组有什么好处吗?(数组和集合的区别有哪些?)
优点 |
缺点 |
|
数组 |
在内存中连续存储,快速修改元素 |
|
ArrayList集合 |
|
ArrayList不是类型安全的 |
可以将集合看作为“长度可变的,具有很多方法的数组”
有哪些缺点?
ArrayList不管是什么对象都是接受的,因为在它眼里所有元素都是Object,这就使得如果‘arrayAnima.Add(123);’或者‘arrayAnima.Add("HelloWorld");’在编译时都是没有问题的,但在执行时,‘foreach(Animal item in arrayAnima)’需要明确集合中的元素是Anima类型,而123是整型,HelloWorld是字符串型,这就会在运行到此处时报错,显然,这是典型的类型不匹配错误,换句话说,ArrayList不是类型安全的。
ArrayList对于存放值类型的数据,比如int、string型(string是一种拥有值类型特点的特殊引用类型)或者结构struct的数据,用ArrayList就意味着都需要将值类型装箱为Object对象,使用集合元素时,还需要执行拆箱操作,带来很大的性能损耗。
装箱(boxing)、拆箱是什么?
- 装箱:把值类型“赋值”给引用类型
- 拆箱:将引用类型“赋值”给值类型
例子:比如整型变量i被“装箱”并赋值给对象o
装箱前,数据类型不必匹配,无法赋值:
装箱后: int a = 1; object b = (object) a; //boxing,分配并构造一个全新的对象 拆箱: o = 1; i=(int) o;
如何使用集合?
命名空间:引用 System.Collections
常用的方法
Count:获取长度 arrayList.Clear(); 清空集合 arrayList.Contains(1); 判断这个集合中是否包含1这个元素 arrayList.Insert 插入 int num = arrayList.Count; 集合中元素的个数 int num = arrayList.IndexOf(2); 找某一个元素对应的索引 删除数据:Remove() 、RemoveAt() 、Clear() int[] nums = {1,2,3}; arrayList.InsertRange(4,nums); 往某一个索引位置插入一个数组 arraylist.AddRange(nums)里面可以放数组、集合 arrayList.LastIndexOf() ; 找最后一个元素的索引 arrayList.Remove(1); 移除某一个元素(只移除最开始出现的) arrayList.RemoveAt(1);移除索引对应的值 arrayList.RemoveRange(3,4) 从指定索引处开始移除,移除多少个,如果超出索引报异常 arrayList arrayList = new ArrayList(); for {int in = 0; int < 100 ; i++} //循环0-100的数 { arrayList.Add(i); //循环输出数 } arrayList.Reverse(); 反转 arrayList.Sort() 排序
实例
int[] nums = new int[] { 1, 2, 3, 4, 5, 6 }; //int类型数组 ArrayList arrayList = new ArrayList(); //实例化一个ArrayList集合对象 arrayList.Add(10); //往集合里面添加一个int类型的值10 arrayList.Add(20); //往集合里面添加一个int类型的值 arrayList.Add("小苏"); //往集合里面添加一个string类型的值 arrayList.Add('女'); //往集合里面添加一个char类型的值 arrayList.Add(true); //往集合里面添加一个bool类型的值 arrayList.Add(3.15m); //往集合里面添加一个decimal类型的值 arrayList.Add(78.9); //往集合里面添加一个double类型的值 arrayList.Add(nums); //往集合里面添加一个数组 //Person per = new Person("小杨",'男',18); //arrayList.Add(per); //可以写成: arrayList.Add(new Person("小杨", '男', 18)); //往集合里面添加一个类 for (int i = 0; i < arrayList.Count; i++) //遍历这个集合,i++ { if (arrayList[i] is int[]) //如果集合i里面的元素能够转换为int类型,强转 { int[] numbers = (int[])arrayList[i]; //就把集合里面的元素赋给这个数组numbers for (int j = 0; j<numbers.Length; j++) //循环numbers这个数组 { Console.WriteLine(numbers[j]); //把数组里面的元素也循环展示出来, } } else if (arrayList[i] is Person) //否则如果集合中的某个元素是Person这个类 { ((Person) arrayList[i]).Show(); //输出类这个方法 } else //否则 { Console.WriteLine(arrayList[i]); //输出集合的结果 } }
定义集合时添加数组
int[] nums = new int[] { 1, 2, 3, 4, 5, 6 }; ArrayList arrayList = new ArrayList(nums); //初始集合里面就包括nums数组里的元素 arrayList.Add(1); arrayList.Add("老牛"); arrayList.AddRange(nums); //把数组中的所有元素输出出来 arrayList.Add(nums); //不会输出数组内容 for (int i = 0; i < arrayList.Count ; i++) { Console.WriteLine(arrayList[i]); }
在数组里面插入元素和修改元素都很困难,所以到了集合,就把那些增删改的方法封装成一个接口,把这些方法放在接口里面,想用随时调用就可以了,克服了数组的缺点。
那如何解决集合的装箱拆箱带来的性能损耗问题?
在C#2.0出版后,推出泛型解决这个问题
泛型(List)
泛型是什么?
??是具有占位符(类型参数)的类、结构、接口和方法,这些占位符是类、结构、接口和方法所存储或使用的一个或多个类型的占位符。
有什么作用呢?
??可以将类型参数用作它所存储的对象的类型的占位符;类型参数作为其字段的类型和其方法的参数类型出现。
有什么特点吗?
- 就是为了专门处理某种类型
- 在尖括号中写什么类型,这个集合就变成了什么类型的集合
- 添加数据、插入数据、索引访问数据都是这个类型的,不用考虑所有的转换问题
泛型和集合的区别
- arrayList集合:不知道存什么类型,不知道存多少个
- List:知道存什么类型,不知道存多少个
实例
static void Main(string[] args) { List<int> list = new List<int>(); //实例化int类型 //随机的往这个List集合中添加十个数字,不能重复,求和,求最大值,求最小值,求平均值 Random r = new Random(); int num = 0; while (list.Count !=10) { num = r.Next(1, 100); if (!list.Contains (num)) { list.Add(num); } } Console.WriteLine("最大值:{0}",list.Max ()); Console.WriteLine("最小值:{0}",list.Min ()); Console.WriteLine("和为:{0}",list .Sum ()); Console.WriteLine("平均值为:{0}",list.Average ()); Console.ReadKey(); List<string> listStr = new List<string>(); //实例化string类型 listStr.Add("哈哈,小杨又变帅了"); }
那如何选择使用哪一个集合呢?
通常情况下都建议使用泛型集合,因为这样可以获得类型安全的直接优点而不需要从基集合类型派生并实现类型特定的成员。此外,如果集合元素为值类型,泛型集合类型的性能通常优于对应的非泛型集合类型(并优于从非泛型基集合类型派生的类型),因为使用泛型时不必对元素进行装箱。
思维导图