第二阶段_第四家小节_C#基础2
第三小节
方法重载
//方法重载:方法名称相同,参数列表不同
//适用性:在不同条件下,解决同一类问题
//优点:让调用者解决一类问题,记忆1个方法。
要求:返回值相同
练习分钟小时的重载
ref——引用参数
引用参数,为地址,相当于指针。
out——输出参数
输出参数类似引用参数,但输出参数在函数中必须修改,调用方法前可以不赋值。
一维数组
数组读取
练习
录入成绩练习
获取最大值练习
数组写法与练习
计算今年第几天
练习自学Array的方法
Forreach
:只能读
:全部
依次读取全部元素。
数组简元素进行比较
冒泡排序
缺点:通常交换次数过多。
选择排序(性能提升)
Params
意义:简化调用者的调用难度。
形式用法:
调用:
-
二维数组
形式:
从下到上,从右到左
声明
从左到右,从上到下
从右到左,从下到上
用法:
arr.length//表示行数*列数;
arr.Getength(0);// 行数
arr.Getlength(1);// 列数
相关语法
Array 数组基类(父类)
object 万类之祖
var 隐式(推断)类型
Array的API
交错数组
特点:参差不齐的数组
长短不一的数组,交错数组的每个元素都是一维数组。
[1][ ][2]
[ ][ ][ ][3][ ]
[ ][ ][4][ ]
创建具有3个元素的交错数组(3行)
int[][] array;
array = new int[3][];--->前边方括号填包括几个一维数组,后边方括号里不能加东西
赋值:
array[0] = new int[3];
array[1] = new int[5];
array[2] = new int[4];
长度可相同。
//将数据1赋值给交错数组的第一个元素的第1个元素
array[0][0] = 1;
array[0][2] = 2;
array[1][2] = 3;
array[2][1] = 4;
读取array:(遍历交错数组)
foreach(var item in array)
{
foreach(var element in item)
{
Console.WriteLine(element);
}
}
//交错数组.Length 交错数组元素总数(行数)
//交错数组[索引].Length 交错数组元素的元素总数(某一行的列数)
for(int r=0;r<array.Length;r++)//交错数组的元素数
{
for(int c =0;c<array[r].Length;c++)//交错数组第一个元素的元素数
{
Console.WriteLine(array[r][c]);
}
}
形式:
float[][] arr3 = new float[3][];
//创建一维数组赋值给交错数组的第一个元素
arr3[0] = new float[2];
arr3[1] = new float[4];
arr3[2] = new float[3];
//将数据1赋值给交错数组的第一个元素的第二个元素
arr3[0][1] = 1;
arr3[1][0] = 2;
arr3[2][2] = 3;
-
获取所有元素
Foreach
foreach (float[] item in arr3)//遍历交错数组的元素(一维数组)
{
foreach (var element in item)//遍历交错数组元素的元素
{
Console.WriteLine(element);
}
}
For
for (int r = 0; r < arr3.Length; r++)
{
for (int c = 0; c < arr3[r].Length; c++)
{
Console.Write(arr3[r][c] +"\t");
}
Console.WriteLine();
}
}
arr3.Length 交错数组的元素数
arr3[0].Length 交错数组第一个元素的元素数
复习
参数数组
使用params关键字定义的
只能用于形参列表
1.原始
-
参数数组
正常数组整数相加
整数相加需求//参数个数不确定,类型确定
形式:
static int Add(int[] arr)
调用:
Int sum =add(new int[]{1,2,3,4,5});
参数数组整数相加
形式:
整数相加需求//参数个数不确定,类型确定
static int Add(params int[] arr)
调用:
Int sum =add(1,2,3,4,5);
对于调用者来说更方便,对于方法内部而言,就是普通一维数组
整数相加的方法:(个数不确定,类型能确定)
用到params的数组要放在形参最后面, Add(int a,params int[] arr)
private static int Add(params int[] arr)【params 可以使调用者直接传递一组数据类型相同的变量集合,也可以不传】
{
int sum;
for(int i =0;i<arr.Length;i++)
{
sum+=arr[i];
}
}
foreach也可,因为foreach只对自身只读,这里是sum 变化,foreach不变化
Main()
{
//int a=Add(new int[]{1,2,3,4,5});
int a = Add(1,2,3,4,5);---->用了params 就不用再new int[]
int b = Add();--->用了params也可以不传
}
复习
**练习
答案
private static void Main2()
{
int[] myTicket = BuyTicket();
Console.WriteLine("我买的**:");
PrintTicket(myTicket);
Console.WriteLine("验证我的中奖潜力……");
int count = 0;
int level;
do
{
count++;
int[] ticket = CreateTicket();
//购买**与开奖**对比
level = TicketEquals(myTicket, ticket);
Console.WriteLine("*********开奖号码:*********");
PrintTicket(ticket);
if (level != 0)
Console.WriteLine("恭喜,{0}等奖。累计花费:{1}元", level, count * 2);
} while (level != 1);
}
private static int[] BuyTicket()
{
int[] ticket = new int[7];
for (int i = 0; i < ticket.Length - 1; )
{
Console.WriteLine("请输入第{0}个红球号码:", i + 1);
int redNumber = int.Parse(Console.ReadLine());
if (redNumber < 1 || redNumber > 33)
Console.WriteLine("您输入的数字超过红球号码范围:1--33");
//[重点:判断输入的号码在数组中是否存在]
else if (Array.IndexOf(ticket, redNumber) >= 0)
Console.WriteLine("当前数字已经存在,请重新录入");
else
ticket[i++] = redNumber;
}
int blueNumber;
do
{
Console.WriteLine("请输入篮球号码:");
blueNumber = int.Parse(Console.ReadLine());
if (blueNumber >= 1 && blueNumber <= 16)
ticket[6] = blueNumber;
else
Console.WriteLine("请输入数字超过篮球号码:1--16");
} while (blueNumber < 1 || blueNumber > 16);//数字不在1--16之间 再次执行
return ticket;
}
private static Random ran = new Random();
private static int[] CreateTicket()
{
int[] ticket = new int[7];
//[重点:生成多个不重复的随机数]
for (int i = 0; i < 6; )
{
//思路:生成随机数,判断是否存在,不在则存储
int num = ran.Next(1, 34);
if (Array.IndexOf(ticket, num) == -1)
ticket[i++] = num;
}
ticket[6] = ran.Next(1, 17);
//红球号码排序[重点:指定范围的排序]
Array.Sort(ticket, 0, 6);
return ticket;
}
private static int TicketEquals(int[] myTicket1, int[] ranTicket2)
{
//判断红球号码中奖数量
//思路:我的第1个号码在随机**的红球号码段中是否存在
// 我的第2个号码在随机**的红球号码段中是否存在
//[重点:在指定范围内检查是否具有相同元素]
int redCount = 0;
for (int i = 0; i < 6; i++)
{
if (Array.IndexOf(ranTicket2, myTicket1[i], 0, 6) != -1)
redCount++;
}
int blueCount = myTicket1[6] == ranTicket2[6] ? 1 : 0;
int level;
if (redCount + blueCount == 7)
level = 1;
else if (redCount == 6)
level = 2;
else if (redCount + blueCount == 6)
level = 3;
else if (redCount + blueCount == 5)
level = 4;
else if (redCount + blueCount == 4)
level = 5;
else if (blueCount == 1)
level = 6;
else
level = 0;
return level;
}
private static void PrintTicket(int[] ticket)
{
for (int i = 0; i < ticket.Length; i++)
{
Console.Write(ticket[i] + "\t");
}
Console.WriteLine();
}
输出#号练习
冒泡排序:发现【更】小的则交换
图片
代码
//缺点:通常交换次数过多。
private static int[] OrderBy1(int[] array)
{
//1.取数据
for (int r = 0; r < array.Length - 1; r++)
{
//2.比较
for (int c = r + 1; c < array.Length; c++)
{
//3.发现更小则交换
if (array[r] > array[c])
{
int temp = array[r];
array[r] = array[c];
array[c] = temp;
}
}
}
return array;
}
-
选择排序:发现【最】小的则交换
图片
代码
private static int[] OrderBy(int[] array)
{
//1.取数据
for (int r = 0; r < array.Length - 1; r++)//轮
{
//2.查找最小索引
int minIndex = r;//假设下当前元素就是最小索引
for (int c = minIndex +1; c < array.Length; c++)//次
{
//发现更小的元素
if (array[minIndex] > array[c])
{
//记录位置(替换假设的最小索引)
minIndex = c;
}
}
//3.交换
if (minIndex != r)
{
int temp = array[minIndex];
array[minIndex] = array[r];
array[r] = temp;
}
}
return array;
}
2048核心算法
//*******************2048核心算法*****************************************
/*需求分析1.0
1.向上移动
--- 获取列数据,形成一维数组
* --- 去除零元素(将非零元素向前移动)
* ---合并数据
* -- 如果相邻元素相同
* -- 将后一个元素累加到前一个元素上
* -- 将后一个元素清零
* --- 去除合并过程中产生的零元素(将非零元素向前移动)
* --- 还原列数据
*
2.向下移动
--- 获取列数据,形成一维数组
* --- 去除零元素(将非零元素向后移动)
* ---合并数据
* -- 如果相邻元素相同
* -- 将前一个元素累加到后一个元素上
* -- 将前一个元素清零
* --- 去除合并过程中产生的零元素(将非零元素向后移动)
* --- 还原列数据
*
需求分析2.0
1.向上移动
--- 获取列数据(从上到下),形成一维数组
--- 调用合并数据方法
* --- 还原列数据(从上到下)
*
2.向下移动
--- 获取列数据(从下到上),形成一维数组
--- 调用合并数据方法
* --- 还原列数据(从下到上)
*
3.合并数据
* --- 调用去除零元素
* ---合并数据
* -- 如果相邻元素相同
* -- 将后一个元素累加到前一个元素上
* -- 将后一个元素清零
* --- 调用去除零元素
4.去零方法(将非零元素向前移动)
*/
答案
移动零
private static void RemoveZero(int[] array)
{
//创建新数组0 0 0 0
int[] newArray = new int[array.Length];
int newIndex = 0;//新数组索引
//将参数中非零元素,依次存入新数组2 2 2 0
for (int i = 0; i < array.Length; i++)
{
if (array[i] != 0)
{
newArray[newIndex++] = array[i];// 存入 自增
}
}
//返回新数组
//return newArray;
//array = newArray;//修改栈中引用
newArray.CopyTo(array, 0); //拷贝元素 array[0] = newArray[0];
}
合并相同项
private static void Merge(int[] array)
{
RemoveZero(array);//2 0 2 2 --> 2 2 2 0
//合并数据
for (int i = 0; i < array.Length-1; i++)
{
//非零 且 相邻相同
if (array[i] !=0 && array[i] == array[i + 1])
{
array[i] += array[i + 1];
array[i + 1] = 0;
}
}
RemoveZero(array);
//return array;
}
向上移动
private static void MoveUp(int[,] map)
{
int[] mergeArray = new int[map.GetLength(0)];
for (int c = 0; c < map.GetLength(1); c++)
{
//00 10 20 30
for (int r = 0; r < map.GetLength(0); r++)//从上到下 获取列数据
mergeArray[r] = map[r, c];
Merge(mergeArray);
for (int r = 0; r < map.GetLength(0); r++)//从上到下 还原列数据
map[r, c] = mergeArray[r];
}
//return map;
}
向下移动
private static void MoveDown(int[,] map)
{
int[] mergeArray = new int[map.GetLength(0)];
for (int c = 0; c < map.GetLength(1); c++)
{
//30 20 10 00
for (int r = map.GetLength(0) - 1; r >= 0; r--)
mergeArray[3 - r] = map[r, c];//正向存入一维数组
Merge(mergeArray);
for (int r = map.GetLength(0) - 1; r >= 0; r--)
map[r, c] = mergeArray[3 - r];
}
//return map;
}
输出显示
private static void PrintMap(int[,] map)
{
for (int r = 0; r < map.GetLength(0); r++)
{
for (int c = 0; c < map.GetLength(1); c++)
{
Console.Write(map[r, c] + "\t");
}
Console.WriteLine();
}
}
//移动 Move(1 , map)
//导医
移动
private static void Move(int direction,int[,] map)
{
switch (direction)
{
case 0:
MoveUp(map);
break;
case 1:
MoveDown(map);
break;
}
}
//目的:让2048算法使用者,可以只记忆一个Move方法。
移动重写
private static void Move(MoveDirection direction, int[,] map)
{
switch (direction)
{
case MoveDirection.Up:
MoveUp(map);
break;
case MoveDirection.Down:
MoveDown(map);
break;
}
}
主函数
static void Main()
{
int[,] map = new int[4, 4]
{
{ 2,4,0,4 },
{ 0,2,2,4 },
{ 2,0,0,2 },
{ 4,2,2,0 }
};
PrintMap(map);
Console.WriteLine("向上移动");
//MoveUp(map);//用户需要记忆的方法过多
//Move(0, map);//用户输入的方向不明确
Move(MoveDirection.Up, map);//限定了取值范围
PrintMap(map);
Console.WriteLine("向下移动");
//MoveDown(map);
Move(MoveDirection.Down, map);
PrintMap(map);
}
数据类型
类型图示
值类型和引用类型图示
Int[] arr;//在栈中声明。A为位地址
arr= new int[]{1}
没有【】就是改栈(重新开辟空间,附地址),有就是改堆。
String a="1"
String b=a
B="5"
得
S2="1"
面试:Stringbuilder与string的区别于优越性差异
应用1:赋值
图示
代码
static void Main3()
{
//方法执行在栈中
//方法内部声明的变量,都在栈中分配空间。
int a;//在栈中
a = 1;//数据1在栈中( 因为值类型直接存数据 )
int b = a;//a将存储的数据赋值b
a = 2;//修改栈中存储的数据
Console.WriteLine(b);//?
//arr:数组的引用
int[] arr;//在栈中
arr = new int[] { 1 };//数组对象在堆中(引用类型数据在堆中)
int[] arr2 = arr;//arr将存储的引用赋值给arr2
//arr[0] = 2;//修改堆中存储的数据(数组对象)
arr = new int[] { 2 };//修改栈中存储的引用
Console.WriteLine(arr2[0]);//?
string s1 = "老王";
string s2 = s1;//s1将存储的引用赋值给s2
s1 = "老宋";//修改栈中存储的引用,重新开辟空间存储"老宋",替换栈中引用
Console.WriteLine(s2);//?
object o1 = 100;
object o2 = o1;//将o1存储的引用赋值给o2
o1 = 200;//修改栈中存储的引用,重新开辟空间存储200,替换栈中引用
Console.WriteLine(o2);//?
}
应用2:比较
图示
代码
static void Main4()
{
//值类型存数据,比较数据
int a = 1, b = 1;
bool r1 = a == b;//比较数据1
Console.WriteLine(r1);//true
//引用类型存引用,比较引用
int[] arr01 = { 1 }, arr02 = { 1 };
bool r2 = arr01 == arr02;//比较数组引用
bool r3 = arr01[0] == arr02[0];//比较数组元素
Console.WriteLine(r2);//?
}
应用3:传参
图示
代码
static void Main5()
{
int a1 = 1;
int[] arr1 = { 1 };
Fun1(a1, arr1);//a1将存储的数据1、arr1将存储的引用 传入方法
Console.WriteLine(a1);//?1
Console.WriteLine(arr1[0]);//?2
int a2 = 1;
Fun2(ref a2);//将a2自身地址传入方法
Console.WriteLine(a2);//2
//区别2:输出参数进入方法前可以不赋值
int a3;//意图:接收方法的结果
Fun3(out a3);//将a2自身地址传入方法
Console.WriteLine(a3);//2
}
方法参数:值参数、引用参数、输出参数
根据传递方式进行的划分。
值参数:按值传递 --- 传递实参变量所存储的内容
作用:传递信息
局部变量:在栈中,全局变量,不在
方法内种局部变量,为
private static void Fun1(int a,int[] arr)
{
//结论:引用类型,方法内部修改堆中数据,影响实参。
a = 2;
arr[0] = 2;//堆中数据
//arr = new int[] { 2 };//修改栈中引用
}
引用参数:按引用传递 --- 传递实参变量自身引用(内存地址)
//作用:改变数据
private static void Fun2(ref int a)
{//方法内部修改形参,等同于修改实参
a = 2;
}
输出参数:按引用传递 --- 传递实参变量自身引用(内存地址)
//作用:返回结果
private static void Fun3(out int a)
{//区别1:方法内部必须修改输出参数
a = 2;
}
static void Main6()
{
int num01 = 1, num02 = 2;
SwopNumber(ref num01, ref num02);
int area,per;
CalculateRect(10, 20, out area, out per);
string input = Console.ReadLine();
//int atk = int.Parse(input);
//尝试着转换,如果成功通过输出参数返回结果。
// 如果失败,可以通过返回值获取结果。(木有异常)
int result;
if (!int.TryParse(input, out result))
{
Console.WriteLine("失败喽");
}
}
-
应用练习
交换两个整数
矩形面积
装箱yu拆箱
面试:发生拆装箱的数目
例子:
ILspy
没有拆装箱,int number…….
Concat字符串拼接,本质是由concat,装箱。。。。。。结局方案。.Tostring
Int->object形参为object
如果形参object,实参值类型,产生装箱操作。
解决方案
1.
2.泛型:可以将数据类型作为参数传入。
Private static void Fun2<Type>(To){
}
调用:Fun2<int>(To);
//如果形参object类型,实参值类型。会产生装箱操作。
//解决方案:1.重载 2.泛型:可以将数据类型作为参数传入方法。
String
特性1:字符串池(字符串常量)
// 节省内层
string s1 = "老王";
string s2 = "老王";
//s1 / s2 是同一对象
string s3 = new string(new char[] { '老', '宋' });
string s4 = new string(new char[] { '老', '宋' });
//s3 / s4 不是同一对象
特性2:不可变性
// 如果可变,就会破坏其他对象的内存空间
string s5 = "张飞";
s5 = "夏军军";//重新开辟空间 存储新字符串,替换栈中引用。
//s5[0] = '夏';
char c1 = s5[0];
Console.WriteLine(s5);//? "张飞" -改变-> "夏军"
string s6 = "老";
string s7 = s6 + "王";//"老王" 与 s1/s2 不是同一对象 "字符串变量参与的拼接,没有使用字符串池的特性"
string s8 = string.Empty;//""
for (int i = 0; i < 10; i++)
{
//每次拼接都会产生一个新对象,产生1个垃圾
s8 = s8 + i.ToString();
//"" + "0"
//"0" +"1"
//"01" +"2"
}
Console.WriteLine(s8);//?
可变字符串
String和stringbuilder的优缺点
重点与练习