数组
和其他编程语言一样 C# 中也支持数组,数组是一个用来存储相同类型数据的、固定大小的、具有连续内存位置的顺序集合。数组中的每个元素都对应一个索引值,索引从 0 开始依次递增,我们可以通过索引来访问数组中的指定元素。
假如我们要存储 100 名学生的分数,若使用普通变量的话可能需要定义 100 整型变量,例如 number0、number1、...、number99。而如果使用数组就简单的多了,只需要定义一个长度为 100 的整型数组,例如 numbers,然后使用 numbers[0]、numbers[1]、...、numbers[99]([ ]
中的数字就是数组的索引)就可以访问数组中的每个元素。
所有数组都是由连续的内存位置组成,最低的内存地址对应第一个元素,最高的内存地址对应最后一个元素,如下图所示:
当程序中需要对一批数据进行批量操作的时候,我们不可能一个一个的去定义变量来存储数据,而是采用容器技术,去批量的一次性存储或者是运算该批数据。
我们可以通过容器去批量的进行操作
在程序当中容器主要是用来批量的存储和计算顺序的
而数组就是容器的一种技术
数组定义
//动态定义、静态定义 //语法格式 /* 数据类型[] 数组名称=数组值 */
数组使用
我们可以通过数组的索引值来访问数组上对于的数据,索引值从0开始 最大索引值为数组的长度减一
访问数组中的数据语法格式:数组名称[索引值]
数组长度语法格式:数组名称.Length
备注:
数组中存储的每一个数据都有对应的索引值,索引值是从0开始的,0代表数组中的第一个元素,最后一个位置为数组名称.Length-1
数组定义后,里面存储的数组必须为同一种数据类型,比如int数组里只能有int类型的数据
数组长度定义后,长度固定,不能更改
对数组进行访问,赋值,修改都是通过数组的索引来实现的,语法格式 数组名称[索引值]
数组计算
-
最值计算
-
平均值
-
总和值
-
排序
-
增删改查
-
数组去重
数组排序
冒泡排序
//冒泡排序实现思路:每次取数组中的相邻元素进行大小比较,如果前面元素大于后面元素,就交换前后两个元素值。经过一轮之后,找到了当前可排元素数组中的最大值放到了数组的最后一个位置上。每一轮都会找到最大值放到了最后一个位置上。每一轮都是从第一个值开始进行比较。 //冒泡排序需要使用for循环结构 int[] a = { 23, 43, 5, 56, 567, 676, 7, 85, 435, 5657, 68778, 7998, 456878, 45654 }; int b = 0; for (int i = 0; i < a.Length ; i++) { for (int j = i + 1; j < a.Length ; j++) { if (a[i] > a[j]) {//正常的交换 b = a[i]; a[i] = a[j]; a[j] = b; // 交换两个变量的值 元组操作 (a[j], a[j + 1]) = (a[j + 1], a[j]); } } } for (int i = 0; i < a.Length; i++) { Console.Write(a[i] + " "); }
选择排序
int[] a = { 2, 45, 6, 64, 46, 76, 8, 34, 534, 5465, 476, 356, 547, 6585, 67, 35, 347, 568, 563, 53, 46, 458, 67, 3464567 }; int b = 0; int c; for (int i = 0; i < a.Length; i++) { c = i; for (int j = i + 1; j < a.Length; j++) { if (a[c] > a[j]) { c = j; } } if (c != i) { b = a[i]; a[i] = a[c]; a[c] = b; } } for (int i = 0; i < a.Length; i++) { Console.Write(a[i] + " "); }
数组增删改查
crud-->增删改查
c-->create 增加
r--->retrieve检索(查找)
u--->update修改
d-->delete删除
增加
int[] arr = { -10, -8, 110, 200, 1, 2, 3, 5, 7, 10 }; // 往arr数组中新增一个119 末位添加 //arr[arr.Length] = 119; 数组有定长特性 一旦声明过后,长度固定,不可变 // 实现思路: 创建一个新数组(原来数组的长度+1),把原来数组中的值赋值给新数组,然后末位添加一个,最后再替换 int[] newArr = new int[arr.Length+1]; // 遍历原来数组,依次取出原来数组中的值对位赋值给新数组 for (int i = 0; i <= arr.Length - 1; i++) { newArr[i] = arr[i]; } newArr[newArr.Length - 1] = 119; // 最后替换 arr = newArr; // 遍历查看 //for (int i = 0; i <= arr.Length - 1; i++) //{ //} // 只是纯粹查看数组中存储的值,可以使用for-each结构 /* 语法结构: 迭代器技术 Iterable foreach(数据类型 变量名称 in 数组名称) { // 变量名称就是数组中对应的具体的值 Console.WriteLine(变量名称); } */ foreach (int i in arr) { Console.WriteLine(i); }
// 指定位置添加数据 int[] newArr = new int[arr.Length + 1]; // 遍历原来数组 int index = 0; for (int i = 0; i <= arr.Length - 1; i++) { // 指定位置在200的前面 120 if (arr[i] == 200) { newArr[index] = 119;// index = 3 index++;// 让索引往后移动一位 newArr[index] = arr[i];// 200 } else { newArr[index] = arr[i]; } // 每次赋值之后,新数组的索引值需要往后移动一位 index++; } // 替换 arr = newArr;
删除
// 创建一个新数组 int[] newArr = new int[arr.Length-1]; int index = 0; // 遍历原来数组, 进行对位赋值 for (int i = 0; i <= arr.Length - 1; i++) { // 如果数组元素不等于110, 我就直接赋值, 同时新数组的索引自增1 if (arr[i] != 110) { newArr[index] = arr[i]; index++; } } // 替换 arr = newArr; // 遍历查看 Console.Write("删除110后的数组元素依次为: "); foreach (int i in arr) { Console.Write(i + " "); }
修改
// 把数组中的第四个元素修改为1000; arr[3] = 1000; // 输入你想要删除的位置,输入你想要替换的值 Console.WriteLine("请输入你想要删除的位置(索引): "); int index = int.Parse(Console.ReadLine()); Console.WriteLine("请输入你想要替换的值"); int number = int.Parse(Console.ReadLine()); if (index >= 0 && index <= arr.Length - 1) { arr[index] = number; }
查找
// 查找指定元素是否在数组中存在 // 200是否在数组中存在,如果存在,位置在哪;如果没有找到指定的数据,返回-1 // 遍历这个数组 // 定义一个开关变量 布尔类型变量 //bool state = false; int index = -1; for (int i = 0; i <= arr.Length - 1; i++) { if (arr[i] == 200) { //Console.WriteLine("200在数组中位置为: " + i); //state = true; index = i; break; } } // 直接输出index,从而确定是否查找到 Console.WriteLine("200在数组中位置为: " + index);
数组去重
static void Main(string[] args) { int[] arr = { -10, -8, 110, 200, 1, 2, 110, 5, 110, 10 }; /* 所有的重复元素都去重 */ // 采用标记法 可以把重复的元素替换成-1 原来的相对位置保持不变 /* 先遍历原来数组,两两进行比较,如果有相等元素,前面的元素标记成-1 去掉-1参与比较 统计-1的个数 定义新数组:长度为原来数组的长度-(-1)个数 删除-1元素 替换 遍历查看 */ // 定义一个变量 统计-1的个数 int count = 0; for (int i = 0; i <= arr.Length - 1; i++) { for (int j = i + 1; j <= arr.Length - 1; j++) { if (arr[i] == arr[j] && arr[i] != -1) { count++; arr[i]= -1; } } } // 定义新数组 int[] newArr = new int[arr.Length - count]; // 定义一个自己的索引变量 int k = 0; // 删除-1的元素 for (int i = 0; i <= arr.Length - 1; i++) { if (arr[i] != -1) { newArr[k] = arr[i]; k++; } } // 替换 arr = newArr; // 遍历查看 Console.Write("数组去重之后的元素值依次为: "); foreach (int i in arr) { Console.Write(i+" "); } }
数组初始化
使用动态方式定义了一个数组:int[] arr = new int[5];
在初始化之后,如果开发者没有赋值,系统会自动给新数组中每个位置赋一个默认值。
对于int整数类型的数组来说,系统默认值为0
对于double小数类型的数组来说,系统默认值为0.0
对于string字符串类型的数组来说,系统默认值为null(几乎对于所有的引用类型的数组,默认值都是null)
对于bool布尔类型的数组来说,系统默认值为false
方法函数参数传递分析
值传递,引用传递,输出传递
值传递
指的是:传递一个具体的数据,实参和形参互不干扰,互不影响
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _05_方法传参内存分析 { internal class Program { static void Main(string[] args) { int a = 1; Console.WriteLine("M1方法调用之前,a变量的值为: " + a);// 1 M1(a); Console.WriteLine("M1方法调用之后,a变量的值为: " + a);// 100 实际为1 } // 定义一个方法,方法中有一个参数,类型是int public static int M1(int a)// 值传递 { a = 100; Console.WriteLine("M1方法内部的a参数值为: " + a);// 100 return a; } } }
引用传递
指的是:传递的是该数据在内容当中的地址值,不传递实际的具体值,如果实参和形参同时对内存地址对应的空间的值发生了修改,则就彻底修改
输出传递
使用 return 语句可以从函数中返回一个值,但是使用输出传递则可以从函数中一次性返回多个值。输出传递与引用传递相似,不同之处在于输出传递是将数据从函数中传输出来而不是传输到函数中。 在 C# 中,需要使用 out 关键字来使用输出传递。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _05_方法传参内存分析 { internal class Program { public static void M4(out int a) { a = 100; Console.WriteLine("M4方法内部,a变量的值为: " + a);// 100 } static void Main(string[] args) { int a = 1; Console.WriteLine("M4方法调用之前,a变量的值为: " + a);// 1 M4(out a); Console.WriteLine("M4方法调用之后,a变量的值为: " + a);// 100 } } }
方法递归
方法递归就是指:一个方法直接或者间接的调用自身的一种方法、技术。一般是用来解决套娃模式的类型题(父子问题、包含关系)
文件流:一个文件夹里有一个文件夹,他的字文件夹还有文件夹,一直找到文件
递归就是循环一种实现机制 默认情况下,递归就是死循环 添加退出条件
如果在某一次递归时,返回的不是一个方法调用,而是一个具体的值,那么该递归就跳出,结束了
语法结构:
/定义一个A方法 publicstatic 返回值 A(参数) //方法体主体代码 if(参数==某个值){ return具体值; } return A(参数); public static void Main(string[] args) { Add(100); } //定义一个方法 public static int Add(int n) { return Add(n-1); }
结构:
一般情况下,递归方法内部一定添加边界条件,就是递归的退出条件,阻止递归无限次循环
练习用递归实现1+2+3
static void Main(string[] args) //调用Add()方法 int sum = Add(3); Console.WriteLine(sum);// 6 //定义一个方法--求和方法 2个引用 public static int Add(int n) 当n==1的时候,退出递归返回一个具体值 return 1; } return Add(n - 1) + n;