1、数组简介
- 在内存中,数组存储在连续取悦的内部,因为数组中每个元素的类型形同,则占用的内存大小也一致,所以在访问数组中的元素时,可以直接根据数组在内存中的起始位置以及下标来计算元素的位置。因此数组访问速度很高。
- 在C#中,数组的下标(也称索引)是从0开始的。以后逐个递增,最大索引是数组元素总数减1
- 数组元素可以为任何数据类型,每个数组都有长度,为了方便管理在初始化数组时,必须指定数组的长度,而且一旦指定,长度就不能改变,除非在重新初始化该数组。
2、一位数组
2.1 一维数组的声明
-
一维数组以线性方式存储固定数据的数组元素,它只需要1个索引值即可标识任意一个数组元素
-
声明格式:数据类型[] <数组名称>
-
说明
- 数据类型可以为任意数据类型
- 数组访问之前必须初始化
- 初始化方式有两种:(1)new关键字(2)字面值逗号相隔指定
-
初始化需要注意的问题
- 数组大小与总个数一致,否则编译事变
- 数组大小一定是个常量;
- 数组元素值已知时用字面值声明,元素值未知时,用new关键字
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 数组声明
{
class Program
{
static void Main(string[] args)
{
int a = 10;
//[]中内容就是指定数组长度,{}指定数组内容
//变量声明及初始化——已知变量数组内容的声明
int[] myintArray = { 0, 1, 2, 3, 10 };
string[] mystrArray= {"ab","cd","ef"};
//变量声明及初始化——变量数组内容未知的声明
int[] myintArray2 = new int[100];
string[] mystrArray2 = new string[100];
//两种方法结合,此时元素个数与数组长度必须一一对应
string[] nameArray = new string[3] { "Lucy", "darly", "Ming" };
//数组长度必须是个常量,不能是变量
//string[] namearray = new string[a] { "lucy", "darly", "ming" }; //变量声明长度是错误的
}
}
}
2.2一维数组的使用
一维数组使用时注意:
- 数组索引从0开始,所以访问数组Array[N]的最后一个元素应该为N-1
- 遍历数组时,避免越界(用froeach可以避免越界)
- 一维数组遍历时,应该尽量使用foreach语句,因为foreach会自动检查数组的索引,使其不会出现越界。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _2一位数组的使用
{
class Program
{
static void Main(string[] args)
{
string[] Name = { "张三", "王五", "李四", "赵六" };
//使用数组中的元素是通过索引值来实现的
Console.WriteLine(Name[1]); //输出的是王五
//数组元素的重新赋值
Name[1] = "王八";
Console.WriteLine(Name[1]);
//数组中的遍历元素,即对数组中的所有元素都按次序访问一次且仅一次
for (int i = 0; i < Name.Length; i++)
{
Console.WriteLine(Name[i]);
}
//遍历数组元素最好用的是foreach
foreach (string oneName in Name)
{
Console.WriteLine(oneName);
}
foreach (string oneName in Name) Console.WriteLine(oneName);
Console.ReadKey();
}
}
}
3、二维数组及三维数组的声明
- 声明格式: 数据类型【,】<数组名>
- 初始化同样有两种:(1)new关键字,(2)字面初始化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _3二位数组的声明
{
class Program
{
static void Main(string[] args)
{
string[] FriendName = { "", "", "", "", "" };
//二位数组的声明
string[,] Frind;
//初始化第一种方法:指定字面值,适用于已知元素的内容
String[,] Friend2 = { { "张三", "男" }, { "李四", "女" }, { "王五", "男" }, { "李小华", "女" } };
//初始化第二种方法:new关键字,适用于元素内容位置
string[,] Friedn3;
Friedn3 = new string[5, 2];
string[,] Friend4 = new string[5, 2];
string[,] Friend5 = new string[4, 2] { { "张三", "男" }, { "李四", "女" }, { "王五", "男" }, { "李小华", "女" } };
}
}
}
3.1三维数组声明
有几层花括号嵌套就是几维数组
//三维数组声明[3,2,2],可以简单理解为3个二维数组,这个二维数组由2行2列构成
string[,,] Friend3 = new string[3,2, 2] { { { "张三", "男" }, { "李四", "女" } }, { { "王五", "男" }, { "李小华", "女" } }, { { "小王", "男" }, { "小张", "女" } } };
4 二维数组的使用
针对多维数组,for循环嵌套,有几维数组就需要用几个嵌套,但是foreach只需一条语句就可以访问整个数组元素。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _4二维数组的使用
{
class Program
{
static void Main(string[] args)
{
string[,] Friend = new string[4, 2] { { "张三", "男" }, { "李四", "女" }, { "王五", "男" }, { "李小华", "女" } };
//三维数组声明[3,2,2],可以简单理解为3个二维数组,这个二维数组由2行2列构成
string[,,] Friend3 = new string[3,2, 2] { { { "张三", "男" }, { "李四", "女" } }, { { "王五", "男" }, { "李小华", "女" } }, { { "小王", "男" }, { "小张", "女" } } };
//二维数组的修改(将李四性别改为男)
Console.WriteLine(Friend[1,0]+" "+Friend[1,1]);
Friend[1, 1] = "男";
Console.WriteLine(Friend[1, 0] + " " + Friend[1, 1]);
//三维数组的修改(将王五性别改为女)
Console.WriteLine(Friend3[1, 0, 0] + " " + Friend3[1,0,1]);
Friend3[1, 0, 1] = "女";
Console.WriteLine(Friend3[1, 0, 0] + " " + Friend3[1, 0, 1]);
//遍历二维数组
Console.WriteLine("二维数组遍历for循环嵌套输出");
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 2; j++)
{
Console.Write(Friend[i,j]+"\t");
}
Console.WriteLine();
}
Console.WriteLine("二维数组遍历foreach输出2");
//此种方式是按照最小元素进行遍历,即先取[0,0],[0,1][1,0][1,1]
//不是先取outstr=friend[1],然后ourstr[0],outstr[1]
int m = 0;
foreach (string outstr1 in Friend)
{
Console.Write(outstr1+"\t");
m++;
if (m % 2==0) Console.WriteLine();
}
Console.WriteLine(Friend.Length);
Console.ReadKey();
}
}
}
5、遍历数组
C#数组是由System.Array类派生而来的引用对象,可以使用Array类的属性来对数组进行各种操作
Length:获得数组总元素的个数,
GetLowerBound:获取数组中指定维度的下限
GetUPperBound:获取驻足中指定维度的上线
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _5遍历数组
{
class Program
{
static void Main(string[] args)
{
string[,] Friend = new string[4, 2] { { "张三", "男" }, { "李四", "女" }, { "王五", "男" }, { "李小华", "女" } };
//正序输出
Console.WriteLine("以下是正序输出");
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 2; j++)
{
Console.Write(Friend[i,j]+"\t");
}
Console.WriteLine();
}
// 倒叙输出
Console.WriteLine("以下是倒叙输出");
for (int i = 3; i >=0; i--)
{
for (int j = 1; j >=0; j--) {
Console.Write(Friend[i,j]+"\t");
}
Console.WriteLine( );
}
Console.WriteLine("以下是Length属性");
Console.WriteLine(Friend.Length);
//[4,2] 可以把[4,2]看成一个数组,4的索引值为0代表第一维度,2的索引值是1代表第二维度。
Console.WriteLine("获取第一维度的上限及下限值");
Console.WriteLine( Friend.GetLowerBound(0)); //0代表第一维度,
Console.WriteLine(Friend.GetUpperBound(0));
Console.WriteLine("获取第二维度的上限及下限值");
Console.WriteLine(Friend.GetLowerBound(1)); //1代表第二维度
Console.WriteLine(Friend.GetUpperBound(1));
//查看3行2列
Console.WriteLine("查看3行2列");
Console.WriteLine(Friend[2,1]);
Console.WriteLine(Friend.GetValue(2, 1));
Console.ReadKey();
}
}
}
6、查找数组元素
查找数组元素解决两类问题
- 看这个数组是否存在某个元素
- 获取已知存在元素的索引值
- Indexof:获取元素第一次出现的索引值位置
- LastIndexOf获取元素最后一次出现索引值的位置
- BinarySearch:用于查找元素首次出现的索引值,采用的方法时二分法,相对indexOf要快。因此优先采用此方法。元素存在返回元素周次出现的索引值,不存在返回负值。
- Contains:
Array的contains方法实际是对IList接口中方法的实现,因此使用之前需要将数组转换为该对象
转换格式:((System.Collections.Ilist)需要转换的数组).Contains(寻找的元素)
返回的是bool类型的值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _6查找数组元素
{
class Program
{
static void Main(string[] args)
{
int[] myintArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, 3, 4, 5, 6 };
//想查找是否存在某个元素,比如8
//IndexOf可以查找元素首次出现的位置
//LastIndexOf可以查找元素最后一次出现的位置,
//位置都是从0开始的索引值
//IndexOf与LastIndexOf都返回一个索引值,为整型int
int result;
//IndexOf(参数1,参数2)参数1四我们要查找的数据,参数2要查找的元素
result = Array.IndexOf(myintArray, 8);
Console.WriteLine(result);
//我们常常利用返回值来判断某个数组中是否存在某个元素,存在返回的是一个>=0索引值。不存在是负数
if (result < 0) Console.WriteLine("数组{0}中不存在元素{1}", "myintArray", 8);
else Console.WriteLine("数组{0}中存在元素{1},其所在位置是{2}", "myintArray", 8,result);
//LastIndexOf 返回数组或集合中最后一次出现该元素的一个索引值
Console.WriteLine("5第一次出现的索引值{0},最后一次出现的索引值{1}", Array.IndexOf(myintArray, 5), Array.LastIndexOf(myintArray, 5));
//BinarySearch:用于查找元素首次出现的索引值,采用的方法时二分法,相对indexOf要快。因此优先采用此方法。元素存在返回元素周次出现的索引值,不存在返回负值。
int result2 = Array.BinarySearch(myintArray, 5);
Console.WriteLine("二分法查找元素5是否存在,并返回首次出现的索引值" + result2);
//Array的contains方法实际是对IList接口中方法的实现,因此使用之前需要将数组转换为该对象
//转换格式:((System.Collections.Ilist)需要转换的数组).Contains(寻找的元素)
//返回的是bool类型的值
bool mybool = ((System.Collections.IList)myintArray).Contains(13);
if (mybool) Console.WriteLine("存在该元素");
else Console.WriteLine("不存在该元素");
Console.ReadKey();
}
}
}
7、数组排序
Array中提供了sort和Reverse两种方法
- Sort:正序排序,升序
- Reverse:倒序,降序
使用格式:Array.Sort(数组);Array.Reverse(数组)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 数组排序
{
class Program
{
static void Main(string[] args)
{
//数组排序主要通过Array下得Sort和Reverse进行操作
int[] myintArray = { 1, 2, 4, 5, 3, 9, 6546, 325, 86, 545 };
Console.WriteLine("数组排序前的结果");
foreach (var outint in myintArray)
{
Console.Write(outint + "\t");
}
Console.WriteLine();
//利用sort实现升序排列,并且更改原数组的储存位置
Array.Sort(myintArray);
Console.WriteLine("数组升序排序后的结果");
foreach (var outint in myintArray)
{
Console.Write(outint+"\t");
}
//利用Reverse可是实现数组元素的降序排列,并且更改原数组的储存位置
Array.Reverse(myintArray);
Console.WriteLine("\n数组实现降序排序后");
foreach (var outint in myintArray)
{
Console.Write(outint + "\t");
}
Console.Read();
}
}
}
8、数组合并与拆分
Array提供了copy方法,Copy方法有四个重载,通过该方法可实现数组合并与拆分
使用格式:
- Array.Copy(数组1,数组2,长度)
- Array.Copy(数组1,数组2,Int64的长度)
- Array.Copy(数组1,指定索引,数组2,指定索引,长度)
- Array.Copy(数组1,指定索引,数组2,指定索引,Int64的长度)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _8_数组合并与拆分
{
class Program
{
static void Main(string[] args)
{
int[] num1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] num2 = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };
Console.WriteLine("原数组num1是");
foreach (int outnum in num1) Console.Write(outnum+"\t");
Console.WriteLine("\n原数组num2是");
foreach (int outnum in num2) Console.Write(outnum + "\t");
int[] resultNum = new int[20]; //数组定义后,没有赋值的情况下,有相应默认值
Console.WriteLine("\n初始化的resultnum值");
foreach (int result in resultNum) Console.Write(result + "\t");
Console.WriteLine("\n将num1内的值复制到resultnum后");
Array.Copy(num1, resultNum, 10); //将数组num1从索引值0开始取10个元素,复制到resultnum中
//在resultNum中从索引值0开始存放,num1的第一个元素复制给resultNum[0],第二个元素复制给resultnum[1]
foreach (int result in resultNum) Console.Write(result + "\t");
Console.WriteLine("\n再次将num2的所有元素复制到resultnum中");
Array.Copy(num2, resultNum, 10); //将数组num2内的10个元素,全部复制到resultnum中
//依然是从索引值0开始赋值
foreach (int result in resultNum) Console.Write(result + "\t");
//合并
Console.WriteLine("\n合并后的结果");
Array.Copy(num1, resultNum, 10);
Array.Copy(num2, 0, resultNum, 10, 5); //从num2索引值0开始取5个长度,放入到resultNum并从索引值10开始存放
foreach (int result in resultNum)
{
Console.Write(result+"\t");
}
//拆分
Console.WriteLine("\n拆分后的结果");
int[] resultNum2 = new int[7];
Array.Copy(resultNum, 5, resultNum2, 0, 7);
foreach (int item in resultNum2) Console.Write(item+"\t");
Console.WriteLine("");
Console.ReadKey();
}
}
}
9 ArrayList类中元素的添加
数组一旦给定大小就是固定的了,不能再改。还有一种数组是可以扩充的,即ArryList类,被称为动态数组或集合
使用步骤:
- 引入命名空间System.Collections
- 创建实例;
- 引用对应的属性或方法
9.1 ArrayList类的属性
- Capactiy: 获取或设置ArrayList可包含的元素数
- Count: 获取ArrayList实际包含的元素数
- IsFixedSize:获取一个值,该值指示ArrayList是否具有固定大小
- IsReadOnly:获取一个值,该值指示ArrayList是否为只读
- Item: 获取或设置指定索引处的元素
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace 数组中添加元素
{
class Program
{
static void Main(string[] args)
{
ArrayList myArrayList = new ArrayList(5); //参数是指定集合的大小
//ArrayList的好处是长度不固定,类型随意
//数组的长度是固定的,不能更改的,类型单一,只能为其中一种
Console.WriteLine("myArrayList初始化后有{0}个元素", myArrayList.Count);//此时输出值为0,没有元素
//Add方法用于向Arraylist中添加单个元素,每次只能添加一个
myArrayList.Add(123);
myArrayList.Add('a');
myArrayList.Add(25.6);
myArrayList.Add("mystring");
myArrayList.Add(10L);
Console.WriteLine("使用add方法添加5个元素之后,有{0}个元素", myArrayList.Count);
//AddRang方法用于一次性向ArrayList中添加多个元素,可以是一个数组
string[] mystringArray = { "张三", "李四", "王五", "赵六" };
myArrayList.AddRange(mystringArray);
Console.WriteLine("使用AddRange方法后,有{0}个元素", myArrayList.Count);
//myArrayList.AddRange("字符串", 123, 100L, 23.34, 'a');这样的方式是错误的
//遍历集合元素
//引用类型分为string Object类;Object类是所有类型的基类,
//因为集合中元素可以为任意类型,所以遍历时应该将变量定义为Object,否则有可能报错
foreach (object item in myArrayList)
{
Console.Write(item+"\t");
}
Console.WriteLine();
Console.ReadKey();
}
}
}
10、ArrayList类中元素的删除
ArrayList类中元素的删除有以下四种方法:
- ArrayList变量名.Remove(值);
- ArrayList变量名.RemoveAt(索引值);
- ArrayList变量名.RemoveRange(开始索引值,要删除的个数);
- ArrayList变量名.Clear();清除所有元素
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _10ArrayList元素删除
{
class Program
{
static void Main(string[] args)
{
//Remove(值)
System.Collections.ArrayList myArraylist = new System.Collections.ArrayList();
myArraylist.Add(1);
myArraylist.Add("成功");
myArraylist.Add(25.3);
myArraylist.Add(100L);
myArraylist.Add('b');
string[] mystringArray = { "张三", "李四", "王五", "赵六" };
myArraylist.AddRange(mystringArray);
Console.WriteLine("元素删除前的ArrayList");
foreach (object item in myArraylist)
{
Console.Write(item+"\t");
}
Console.WriteLine("\n删除之后的ArrayList");
myArraylist.Remove(100L);
foreach (object item in myArraylist)
{
Console.Write(item + "\t");
}
Console.WriteLine("\n使用RemoveAt删除张三之后的内容");
myArraylist.RemoveAt(3); //参数为索引值
foreach (object item in myArraylist)
{
Console.Write(item + "\t");
}
//RemoveRange(起始索引,删除个数)
Console.WriteLine("\n删除张三之后的内容后");
myArraylist.RemoveRange(3, 3); //删除内容包含起始索引的内容
foreach (object item in myArraylist)
{
Console.Write(item + "\t");
}
Console.WriteLine("\n清除ArrayList中所有元素");
myArraylist.Clear();
foreach (object item in myArraylist)
{
Console.Write(item + "\t");
}
Console.WriteLine("清除所有元素后数组的长度是"+myArraylist.Count);
Console.ReadKey();
}
}
}
11、ArrayList类中元素遍历与查找
11.1遍历
遍历 foreach语句,object类型
object:ArrayList中存储的类型不一定一致,也不一定能够完全自动转换,所以为避免出错,我们采用object类型
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _11ArrayList元素的遍历与查找
{
class Program
{
static void Main(string[] args)
{
ArrayList myArrayList = new ArrayList(2);
myArrayList.Add("数字:");
int[] myintArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
myArrayList.AddRange(myintArray);
string[] mystringArray = { "张三", "李四", "张三", "赵六" };
myArrayList.AddRange(mystringArray);
foreach (object item in myArrayList) Console.Write(item + "\t");
Console.ReadKey();
}
}
}
11.1元素查找有三个方法
- IndexOf(要查找的元素),返回首次出现的索引整型值,如果查找不到,返回-1
- LastIndexOf(要查找的元素)返回最后一次出现的索引整型值,如果查找不到,返回-1
- BinarySearch(要查找的元素)返回首次出现索引整型值,如果查找不到,返回-1。注意次方法执行时,首相将元素及查找的内容都转换为二进制,但因为动态数组内的元素类型不一致,因此转换二进制过程中可能存在错误。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _11ArrayList元素的遍历与查找
{
class Program
{
static void Main(string[] args)
{
ArrayList myArrayList = new ArrayList(2);
myArrayList.Add("数字:");
int[] myintArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
myArrayList.AddRange(myintArray);
string[] mystringArray = { "张三", "李四", "张三", "赵六" };
myArrayList.AddRange(mystringArray);
foreach (object item in myArrayList) Console.Write(item + "\t");
//元素查找有三个方法
//indexOf(要查找的元素) 返回一个首次出现的索引整型值,如果查找不到,返回-1
Console.WriteLine("张三元素所首次出现位置:" + myArrayList.IndexOf("张三"));
//LastIndex(要查找的元素);返回一个最后一次出现的索引整型值,否则返回-1
Console.WriteLine("张三元素所最后一次出现位置:" + myArrayList.LastIndexOf("张三"));
//BinarySearch() 查找不到返回-1()
//Console.WriteLine("BinarySearch() 查找张三首次出现位置索引值:" + myArrayList.BinarySearch("张三")); //因数组中元素类型不同,导致此语句错误无法正常输出
ArrayList myArrayList2 = new ArrayList(2);
int[] myintArray2 = { 0,1, 2, 3, 4,9, 5, 6, 7, 8, 9 };
myArrayList2.AddRange(myintArray2);
Console.WriteLine("BinarySearch() 查找9首次出现位置索引值:" + myArrayList2.BinarySearch(9)); //因数组中元素类型不同,导致此语句错误无法正常输出
Console.ReadKey();
}
}
}
本章小结及任务实施
冒泡排序
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻两个元素,交换也发生在这两个元素之间。所以,如果两个元素相等则不交换。如果两个相等的元素没有相邻,那么即使通过前面的两辆交换把两个相邻起来,这时也不进行交换。所有相同元素的前后顺序并没有改变。所以冒泡排序是一种稳定的排序算法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _12_小结及案例
{
class Program
{
static void Main(string[] args)
{
//int[] myintArray = { 05, 08, 15, 20, 15, 10 };
int[] myintArray = new int[6];
Console.WriteLine("请输入六个整数,系统自动进行排序");
for (int i = 0; i < myintArray.Length ; i++)
{
myintArray[i] = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("原数组排列顺序");
foreach (int outitem in myintArray)
{
Console.Write(outitem + "\t");
}
Console.WriteLine();
//降序排列
for (int i = 0; i < myintArray.Length-1; i++)
{
int temp;
for (int j = 0; j < myintArray.Length-1-i; j++)
{
if (myintArray[j] < myintArray[j + 1])
{
temp = myintArray[j];
myintArray[j] = myintArray[j + 1];
myintArray[j + 1] = temp;
}
}
}
//遍历
Console.WriteLine("降序排列最终结果");
foreach (int outitem in myintArray)
{
Console.Write(outitem + "\t");
}
//升序排列
for (int i = 0; i < myintArray.Length - 1; i++)
{
int temp;
for (int j = 0; j < myintArray.Length - 1 - i; j++)
{
if (myintArray[j] > myintArray[j + 1])
{
temp = myintArray[j];
myintArray[j] = myintArray[j + 1];
myintArray[j + 1] = temp;
}
}
}
//遍历
Console.WriteLine("\n升序排列最终结果");
foreach (int outitem in myintArray)
{
Console.Write(outitem + "\t");
}
Console.ReadLine();
}
}
}