## 一、选择排序基本原理
新建中间商,依次比较,找出极值(最大值 或者 最小值)放入目标位置 比较n轮
## 二、代码实现
int[] arr = new int[]{3,88,4,11,23,9,6,71,32}
for(int m = 0; m < arr.Length - 1; m++)
{
int index = 0;
for(int n = 1; n < arr.Length - 1 - m; n++)
{
if( arr[index] < arr[n])
{
index = n;
}
}
// 放入目标位置 length - 1 - 轮数
if( index != arr.Length - 1 - m)
{
int temp = arr[index];
arr[index] = arr[arr.Length - 1 - m];
arr[arr.Length - 1 - m] = temp;
}
}
## 一、排序的基本概念
计算机内经常进行的一种操作,目的是将无序的记录序列调整为有序的记录序列
## 二、冒泡排序的基本原理
两两相邻,不停比较,不停交换,比较n轮
```
for(int m = 0, m < arr.length, m++){
for(int n = 0; n < arr.length - 1, n++)
{
if( arr[n] > arr[n+1])
{
int temp = arr[n];
arr[n] = arr[n+1];
arr[n+1] = temp;
}
}
}
```
### 优化
1.确定位置的数字 不用比较,所以每完成n轮后面位置的数,就不用参与比较了
```
for(int m = 0, m < arr.length, m++){
for(int n = 0; n < arr.length - 1 - m, n++)
{
if( arr[n] > arr[n+1])
{
int temp = arr[n];
arr[n] = arr[n+1];
arr[n+1] = temp;
}
}
}
```
2.
```
bool isSort = false;
for(int m = 0, m < arr.length, m++){
for(int n = 0; n < arr.length - 1 - m, n++)
{
if( arr[n] > arr[n+1])
{
isSort = true;
int temp = arr[n];
arr[n] = arr[n+1];
arr[n+1] = temp;
}
}
if(!isSort)
{
break;
}
}
```
## 练习题
### 1
定义一个数组,长度为20,每个元素值随机0~100的数
使用冒泡排序进行升序排序并打印
使用冒泡排序进行降序排序并打印
### 2
写一个函数,实现一个数组的排序,并返回结果。可以根据参数决定是升序还是降序
```
static int[] Bubble(int[] arr, bool reverse = false)
{
bool isSort = false;
for (int m = 0; m < arr.Length; m++)
{
for (int n = 0; n < arr.Length - 1 - m; n++)
{
bool order = reverse ? arr[n] < arr[n + 1] : arr[n] > arr[n + 1];
if (order)
{
isSort = true;
int temp = arr[n];
arr[n] = arr[n + 1];
arr[n + 1] = temp;
}
}
if (!isSort)
{
break;
}
}
return arr;
}
```
## 一、基本概念
结构体 是一种自定义变量类型 类似枚举需要自己定义
它是数据和函数的集合
在结构体中 可以申明各种变量和方法
作用 用来表现存在关系的数据的集合 比如用结构体表现学生 动物 人类等等
## 二、基本语法
⚠️ 结构体的名字我们使用帕斯卡命名法
```
struct 自定义结构体名
{
// 第一部分
// 1.变量
// 第二部分
// 2.构造函数(可选)
// 第三部分
// 函数
}
```
## 三、实例
结构体申明的变量 不能直接初始化
变量类型可以写任意类型 包括结构体 但是 不能是自己的结构体
```
// 表现学生数据的结构体
struct Student
{
public int age;
public char sex;
public int number;
public string name;
void Speak()
{
Console.WriteLine("name: {0}, age: {1}", name, age,)
}
}
```
## 四、结构体的使用
变量类型 变量名
Student s1;
s1.name;
## 五、访问修饰符
修饰结构体中变量和方法 是否能被外部使用
public 公共的 可以被外部访问
private 私有的 只能在内容使用
默认不写 为private
## 六、结构体的构造函数
基本概念
1. 没有返回值
2. 函数名必须和结构体名相同
3. 必须有参数
4. 如果申明了构造函数 那么必须在其中对所有变量数据初始化
构造函数是为了方便外部赋值的
```
// 表现学生数据的结构体
struct Student
{
public int age;
public char sex;
public int number;
public string name;
void Speak()
{
Console.WriteLine("name: {0}, age: {1}", name, age,)
}
public Student(string name, int age, int number, char sex)
{
this.name = name;
this.age = age;
this.number = number;
this.sex = sex;
}
public Student(string name)
{
this.name = name;
this.age =18;
this.number = 1;
this.sex = “男”;
}
}
```
Student2 s2 = new Student("sam", 18, 1, "男")
## 练习题
### 1
使用结构体描述学员的信息,姓名,性别,年龄,班级,专业,创建两个学员对象,并对其基本信息进行初始化并打印
```
using System;
namespace 结构体练习
{
class Program
{
struct Student
{
public int age;
public char sex;
public int number;
public string name;
public string course;
public Student(string name, int age, int number, char sex, string course)
{
this.name = name;
this.age = age;
this.number = number;
this.sex = sex;
this.course = course;
}
public void Speak()
{
Console.WriteLine("name: {0}, age: {1}", name, age);
}
}
static void Main(string[] args)
{
Student s1 = new Student();
s1.Speak();
Student s2 = new Student("sam", 18, 1, '男', "数据分析");
s2.Speak();
}
}
}
```
### 2
请简要描述private和public两个关键字的区别
一个是私有的,只能自己内部调用,一个是公有的可以提供给外部使用
### 3
使用结构体描述矩形的信息,长,宽;创建一个矩形,对其长宽进行初始化,并打印矩形的长、宽、面积、周长等信息。
```
using System;
namespace 结构体练习
{
class Program
{
struct React
{
int length;
int width;
int height;
int area;
int perimeter;
public React(int length, int width, int height)
{
this.length = length;
this.width = width;
this.height = height;
this.area = length * width * height;
this.perimeter = (length + width + height) * 2;
}
public void ReactInfo()
{
Console.WriteLine("length: {0}, width: {1}, height: {2}, area: {3}, perimeter: {4}, ",
length, width, height, area, perimeter);
}
}
static void Main(string[] args)
{
React r1 = new React(5, 1, 2);
r1.ReactInfo();
}
}
}
```
### 4
使用结构体描述玩家信息,玩家名字,玩家职业
请用户输入玩家姓名,选择玩家职业,最后打印玩家的攻击信息
职业:
战士(技能:冲锋)
猎人(技能:假死)
法师(技能:奥术冲击)
打印结果:猎人唐老狮释放了假死
```
using System;
namespace 结构体练习
{
class Program
{
struct Player
{
string name;
string job;
string skill;
public Player(string name, string job)
{
this.name = name;
this.job = job;
switch (job)
{
case "战士":
this.skill = "冲锋";
break;
case "猎人":
this.skill = "假死";
break;
case "法师":
this.skill = "奥术冲击";
break;
default:
this.skill = "";
break;
}
}
public void PlayerInfo()
{
Console.WriteLine("name: {0}, job: {1}, skill: {2}", name, job, skill);
}
}
static void Main(string[] args)
{
Console.Write("请输入您的姓名,回车确认:");
string name = Console.ReadLine();
Console.Write("请输入您的职业,回车确认(职业类型 战士 猎人 法师):");
string job = Console.ReadLine();
Player r1 = new Player(name, job);
r1.PlayerInfo();
}
}
}
```
### 5
使用结构体描述小怪兽
### 6
定义一个数组存储10个上面描述的小怪兽,每个小怪兽的名字为(小怪兽+数组下标)
举例:小怪兽0,最后打印10个小怪兽的名字+攻击力数值
```
using System;
namespace 结构体练习
{
class Program
{
struct Monster
{
int number;
public string name;
public Monster(int number)
{
this.number = number;
this.name = string.Format("小怪兽_{0}", number);
}
}
static void Main(string[] args)
{
Monster[] monsters = new Monster[100];
for (int i = 0; i < 100; i++)
{
monsters[i] = new Monster(i + 1);
Console.WriteLine("generate monster -> {0}", monsters[i].name);
}
}
}
}
```
### 7
应用已学过的知识,实现奥特曼打小怪兽
提示:
结构体描述奥特曼与小怪兽
定义一个方法实现奥特曼攻击小怪兽
定义一个方法实现小怪兽攻击奥特曼
## 一、基本概念
递归函数:就是让函数自己调用自己
static void Func()
{
Func(); // 死循环
}
一个正确的递归函数
1. 必须有结束调用的条件
2. 用于条件判断的条件语句 必须改变 能够达到停止的目的
## 二、实例
打印0~10
static void Func(int a)
{
if( a > 10){
return;
}
Console.WriteLine();
a++;
Func(a); // 死循环
}
Func(0);
## 练习题
### 1
使用递归的方式打印0~10
```
static void Func(int a)
{
if( a > 10){
return;
}
Console.WriteLine();
a++;
Func(a); // 死循环
}
Func(0);
```
### 2
传入一个值,递归求该值的阶乘 并返回
5! = 1*2*3*4*5
```
static int Practice2(int num)
{
if (num == 1)
{
return 1;
}
return num * Practice2(num-1);
}
```
### 3
使用递归求 1! + 2! + 3! + 4! + ..... + 10!
```
static int Practice3(int num)
{
if (num == 1)
{
return 1;
}
return Practice2(num) + Practice3(num - 1);
}
```
### 4
一根竹竿长100m,每天砍掉一半,求第十天它的长度是多少(从第0天开始)
```
static float Practice4(float length, int day)
{
length = length / 2;
if (day == 0)
{
return length;
}
day--;
return Practice4(length, day);
}
```
### 5
不允许使用循环语句、条件语句,在控制台中打印出1-200这200个数(提示:递归+短路)
```
static int Practice5(int num)
{
Console.WriteLine(num);
return num > 1 ? Practice5(num - 1) : 1;
}
```
## 一、基本概念
重载概念:
在同一语句块(class 或者 struct)中函数名相同 参数数量不同 或者参数的数量相同,但是参数的类型或者顺序不同
作用:
1. 命名一组功能相似的函数,减少函数名的数量,避免命名空间的污染
2. 提升程序可读性
## 二、实例
注意⚠️
1. 重载和返回值类型无关,只和参数类型,个数,顺序有关
2. 调用时,程序会根据传入的参数类型判断使用哪个重载
总结:
概念 同一个语句块中,函数名相同,参数数量、类型、顺序不同的函数 就成为我们的重载函数
注意 和返回值无关
作用 一般用来处理不同参数的同一类型的
## 练习题
### 1
请重载一个函数
让其可以比较两个int或两个float或两个double的大小
并返回较大的那个值
static int Max(int a, int b){}
static float Max(float a, float b){}
### 2
请重载一个函数
让其可以比较n个int或n个float或n个double的大小
并返回最大的那个值。(用params可变参数来完成)
static int Max(params int arr){}
static float Max(params float arr){}
static double Max(params double arr){}
## 一、函数语法复习
1. 静态关键词 可选 目前对于我们来说必须写
2. 返回值 没有返回值填void 可以填写任意类型的变量
3. 函数名 帕斯卡命名法
4. 参数可以是0~n个,前面可以加ref out用来传递想要在内部改变内容的变量
5. 如果返回值不是void,那么必须有return对应类型的内容,return可以打断函数语句块中的逻辑,直接停止后面的逻辑
## 二、 变长参数关键词
变长参数关键字 params
static int Sum(params int[arr]){}
Sun(1,2,3,4,5)
注意⚠️
1. params关键词后面必为数组
2. 数组的类型可以是任意类型
3. 函数参数可以有 别的参数和params关键词修饰的参数
4.函数参数中只能最多出现一个params关键词,并且一定是在最后一组参数 前面可以有n个其他参数
## 三、参数默认值
有参数默认值的参数 一般称为可选参数 作用是:当调用函数时可以不传入参数,不传就会使用默认值作为参数的值
注意⚠️
1. 支持多参数默认值 每个参数都可以有默认值
2. 如果要混用 可选参数 必须写在普通参数后面
static int Speak(string str = "test"){}
Speak();
## 练习题
### 1
使用param参数,求多个数字的和以及平均数
```
static int SumSuper(params int[] nums)
{
int sum = 0;
for (int i = 0; i < nums.Length; i++)
{
sum += nums[i];
}
return sum;
}
```
### 2
使用param参数,求多个数字的偶数和奇数和
```
static int[] SumSuper2(params int[] nums)
{
int sum1 = 0;
int sum2 = 0;
for (int i = 0; i < nums.Length; i++)
{
if (nums[i] % 2 == 0)
{
sum1 += nums[i];
}
else
{
sum2 += nums[i];
}
}
return new int[] { sum1, sum2};
}
```
## 一、学习ref和out的原因
他可以解决 在函数内部改变外部传入的内容 里面变了 外面也要变
static void ChangeValue(int value)
{
value = 3;
}
// 这个时候数组中的值变了
static void ChangeArrValue(int[] arr)
{
arr[0] = 3;
}
## 二、ref 和 out 的使用
// 函数参数的修饰符,当传输的值类型参数在内部修改时,或者引用类型参数在内部重新申明时,外部的值会发生变化
### ref
static void ChangeValue(ref int value)
{
value = 3;
}
ChangeValue(ref 8);
### out
static void ChangeValue(out int value)
{
value = 3;
}
ChangeValue(out 8);
## 三、ref 和 out 的区别
1. ref 传入的变量必须初始化 out不用
2. out 传入的变量**必须**在内部赋值(修改) ref不用
## 练习题
### 1
请简要描述ref和out的区别
ref 传入时必须赋值,函数内部无要求
out 传入时可以不初始化,但是在函数内部必须初始化,或者赋值
### 2
让用户输入用户名和密码,返回给用户一个bool类型的登录结果,并且还要单独的返回给用户一个登录信息。
如果用户名错误,除了返回登录结果之外,登录信息为“用户名错误”
如果密码错误,除了返回登录结果之外,登录信息为“密码错误”
```
static bool Login(string name, string password, ref string resultInfo)
{
bool result = name == "admin" && password == "123456" ? true : false;
if (!result)
{
resultInfo = name!= "admin" ? "用户名错误" : "密码错误";
}
return result;
}
```
## 一、基本概念
本质是一块具有名称的代码块,是封装代码进行重复使用的机制
主要作用
1.封装代码
2.提升代码复用率
3.抽象行为
## 二、函数申明在哪里
写在class语句块中,或者struct语句块中
## 三、基本语法
static 返回类型 函数名(参数类型 参数名1, 参数类型2 参数名...)
{
函数的代码逻辑;
}
1.关于static 不是必须的 在没有学习类和结构体之前都是必须的
2.1 关于返回类型 引出一个新的关键字 void(表示没有返回值)
2.2 返回类型 可以写任意的变量类型
3. 关于函数名 使用帕斯卡命名法 MyMethod
4.1 参数不是必须的,可以有0~n个,参数的类型也是可以是任意类型的
4.2参数名 驼峰命名法
5.当返回值类型不为void时 必须通过新的关键词 return返回对应类型的内容(注意⚠️:即使是void也可以选择使用return)
## 四、实际运用
### 1 无参无返回值函数
```
static void MyMethod()
{
}
```
### 2 有参无返回值函数
```
static void MyMethod(int num)
{
}
```
### 3 有无参有返回值函数
```
static string MyMethod()
{
return "test";
}
```
### 4 有参有返回值函数
```
static int MyMethod(int num)
{
return num;
}
```
### 5 有参有多返回值函数
// 函数返回值一定是一个类型 只能是一个内容
```
static int[] MyMethod(int a, int b)
{
return new int[] { sum, avg}
}
```
## 五、关于return
即使函数没有返回值,我们也可以使用return,return可以直接不执行之后的代码,直接返回到函数外部
static void Speak(string str)
{
if()
{
...
return
}
}
## 练习题
### 1
写一个函数,比较两个数字的大小,返回最大值
```
static int Max(int a, int b)
{
return a >= b ? a : b;
}
```
### 2
写一个函数,用于计算一个圆的面积和周长,并返回打印
```
static float[] CirclePerimeterAndArea(int r)
{
float pi = 3.14f;
float perimeter = 2 * pi * r;
float area = pi * r * r;
return new float[] { perimeter, area };
}
```
### 3
写一个函数,求一个数组的总合、最大值、最小值、平均值
```
static int[] NumOperation(int[] nums)
{
int sum = 0;
int avg;
int max = nums[0];
int min = nums[0];
for (int i = 0; i < nums.Length; i++)
{
max = nums[i] > max ? nums[i] : max;
min = nums[i] < min ? nums[i] : min;
sum += nums[i];
}
avg = sum / nums.Length;
return new int[] { sum, max, min, avg};
}
```
### 4
写一个函数,判断你传入的参数是不是质数
```
static bool IsPrimeNumber(int num)
{
if (num <= 1)
{
return false;
}
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
return false;
}
}
return true;
}
```
### 5
写一个函数,判断你输入的年份是否是闰年
闰年判断条件:
年份能被400整除(2000)
或者
年份能被4整除,但是不能被100整除(2008)
```
static bool IsLeapYear(int year)
{
return (year % 400 == 0) || (year % 4 == 0 && year % 100 > 0) ? true : false;
}
```
## 复习值和引用类型
// 值类型 -- 它变我不变 存储在栈内存中
无符号整型 有符号整型 浮点数 char bool 结构体
// 引用类型 -- 它变我也变 存储在堆内存中
数组 string 类
## string的它变我不变
string非常特殊,它具备值类型的特征 它变我不变
string 赋值关系图
string 虽然方便 但是又一个缺点 就是频繁的改变string 重新赋值 会产生内存垃圾
优化替代方案,会在c#核心当中进行讲解
## 通过断点调试
## 一、变量类型的复习
//无符号整型
byte ushort ulong uint
// 有符号整型
sbyte short int long
// 浮点数
float double decimal
// 特殊类型
bool char string
// 复杂类型
enum 数组
### 把以上 学过的 变量类型 分为 值类型和引用类型
#### 引用类型
string 数组 类
#### 值类型
其他、结构体(未学习)
## 二、值类型和引用类型的区别
### 1 使用上的区别
```
// 值类型
int a =10;
// 引用类型
int[] arr = new int[]{1,2,3,4};
// 申明一个b让其等于之前的a
int b = a;
// 申明一个arr2让其等于之前的arr
int[] arr2 = arr;
// 打印观察现象
Console.WriteLine("a={0} b={1}",a,b);
Console.WriteLine("arr[0]={0} arr2[0]={1}",arr[0],arr2[0]);
b = 20;
arr2[0] = 5;
// 打印观察现象
Console.WriteLine("a={0} b={1}",a,b);
Console.WriteLine("arr[0]={0} arr2[0]={1}",arr[0],arr2[0]);
```
值类型 在互相赋值时, 把内容拷贝给了对方 它变我不变
引用类型的互相赋值 是 让两者指向同一个值 它变我也变
### 2 为什么有以上的区别
值类型 和 引用类型 存储在的 内存区域 是不同的 存储方式是不同的,所以造成了使用上的区别
值类型存储在栈空间 -- 系统分配。自动回归,小而快
引用类型 存储在 堆空间 -- 手动申请和释放,大而慢
空间上的差异图
值类型赋值关系图
引用类型赋值关系图
## 练习题
### 1
int a = 10;
int b = a;
b = 20;
Console.WriteLine(a)
请问打印结果为多少?
10
### 2
int[] a = new int[]{10};
int[] b = a;
b[0] = 20;
Console.WriteLine(a[0]);
请问打印结果为多少?
20
### 3
string str = "123";
string str2 = str;
str2 = "321";
Console.WriteLine(str);
请问打印结果为多少?
123
## 一、基本概念
交错数组 是数组的数组 每个维度的数量可以不同
注意⚠️ 二维数组的每行的列数相同,交错数组每行的列数可能不同
## 二、数组中的申明
### 变量类型[][] 交错数组变量名称;
int[][] arr1;
### 变量类型[][] 交错数组变量名称 = new
变量类型[行数][];
int[][] arr2 = new int[3][];
### 变量类型[][] 交错数组变量名称 = new
变量类型[行数][]{ 一维数组1,一维数组2};
int[][] arr2 = new int[3][]{
new int[] { 1, 2, 3},
new int[] { 4, 5, 6},
new int[] { 1 },
};
### 变量类型[][] 交错数组变量名称 = new
变量类型[][]{ 一维数组1,一维数组2};
int[][] arr2 = new int[][]{
new int[] { 1, 2, 3},
new int[] { 4, 5, 6},
new int[] { 1 },
};
### 变量类型[][] 交错数组变量名称 =
{ 一维数组1,一维数组2};
int[][] arr2 = {
new int[] { 1, 2, 3},
new int[] { 4, 5, 6},
new int[] { 1 },
};
## 三、数组的使用
### 1 数组的长度
int[][] arr = {new int[] {1, 2, 3},
}new int[] {4, 5}
Console.WriteLine(arr.GetLength(0));
Console.WriteLine(arr[0].Length);
### 2 获取交错数组中的元素
arr[0][1]
### 3 修改交错数组中的元素
arr[0][1] = 3;
### 4 遍历交错数组
注意不要越界就可以了
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr[i].Length(1); j++)
{
}
}
### 5 增加交错数组的元素
### 6 删除交错数组的元素
### 7 查找交错数组中的元素
## 一、基本概念
二维数组 是使用两个下标(索引)来确定元素的数组
两个下标可以理解成 行标 和 列标
比如矩阵, 可以用int[2,3]表示
123
456
## 二、二维数组的申明
### 变量类型[,] 二维数组变量名;
int[,] arr; // 申明之后在后面进行初始化```
### 变量类型[,] 二维数组变量名 = new 变量类型[行, 列];
int[,] arr = new int[3, 3]
### 变量类型[,] 二维数组变量名 = new 变量类型[行, 列]{{0行内容1, 0行内容2}, {1行内容1, 1行内容2}};
int[,] arr = new int[3, 3]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
### 变量类型[,] 二维数组变量名 = new 变量类型[行, 列]{{0行内容1, 0行内容2}, {1行内容1, 1行内容2}};
int[,] arr = new int[3, 3]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
### 变量类型[,] 二维数组变量名 = new 变量类型[, ]{{0行内容1, 0行内容2}, {1行内容1, 1行内容2}};
int[,] arr = new int[, ]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
## 三、二维数组的使用
### 1 二维数组的长度
int[,] arr = new int[, ]{
{1, 2, 3},
{4, 5, 6}
}
arr.GetLength(0) // 2
arr.GetLength(1) // 3
### 2 获取二维数组中的元素
arr[0,1]
### 3 修改二维数组中的元素
arr[0,1] = 99;
### 4 遍历二维数组
```
int[,] arr = new int[,] { { 1, 2, 3 },
{ 4, 5, 6 } };
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.WriteLine(arr[i, j]);
}
}
```
### 5 增加数组的元素
```
int[,] arr = new int[,] { { 1, 2, 3 },
{ 4, 5, 6 } };
int[,] arr2 = new int[3, 3];
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr2[i, j] = arr[i, j];
}
}
arr = arr2;
```
### 6 删除数组的元素
```
int[,] arr = new int[,] { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9} };
int[,] arr2 = new int[2, 3];
for (int i = 0; i < arr2.GetLength(0); i++)
{
for (int j = 0; j < arr2.GetLength(1); j++)
{
arr2[i, j] = arr[i, j];
}
}
arr = arr2;
Console.Write(arr.GetLength(0));
Console.Write(arr.GetLength(1));
```
### 7 查找数组中的元素
```
int[,] arr = new int[,] { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9} };
int a = 9;
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
if (a == arr[i,j])
{
break;
}
}
}
```
## 练习题
### 1
将1到10000赋值给一个二维数组(100行100列)
```
int[,] arr = new int[100,100];
int num = 10000;
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr[i, j] = num--;
Console.Write("num: {0} ;", arr[i, j]);
}
}
```
### 2
将二维数组(4行4列)的右上半部分置零(元素随机1~100)
```
int[,] arr = new int[4,4];
Random r = new Random();
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr[i, j] = i >= 2 && j >= 2 ? 0 : r.Next(1, 100);
}
}
```
### 3
求二维数组(3行3列)的对角线元素的和(元素随机1~10)
```
int[,] arr = new int[3,3];
Random r = new Random();
int sum = 0;
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr[i, j] = r.Next(1, 100);
// 下标相加 能被2整除
if ( (i + j) % 2 == 0)
{
sum += arr[i, j];
}
Console.WriteLine("{0} \t", arr[i, j]);
}
}
Console.WriteLine(sum);
```
### 4
求二维数组(5行5列)中最大元素值及其行列号(元素随机1~500)
```
int[,] arr = new int[5,5];
Random r = new Random();
int max = 0;
int col = 0;
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
arr[i, j] = r.Next(1, 500);
if ( arr[i, j] >= max)
{
max = arr[i, j];
col = i;
}
}
}
Console.WriteLine("col {0}, max {1}", col, max);
```
### 5
给一个M*N的二维数组,数组元素的值为0或者1,要求转换数组,将含有1的行和列全部置1
```
int[,] arr = new int[5, 5] {
{ 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0},
{ 0, 1, 0, 0, 0},
{ 0, 0, 1, 1, 0},
{ 0, 0, 0, 0, 0}
};
Random r = new Random();
bool[] col = new bool[5];
bool[] raw = new bool[5];
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
//arr[i, j] = r.Next(0, 2);
if (arr[i ,j] == 1)
{
col[i] = true;
raw[j] = true;
}
Console.Write("num: {0} ", arr[i, j]);
}
Console.Write("\n");
}
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
if ( col[i] || raw[j])
{
arr[i, j] = 1;
}
Console.Write("num: {0} ", arr[i, j]);
}
Console.Write("\n");
}
```
## 基本概念
// 数组是存储一组相同类型数据的集合
// 数组分为 一维、多维
// 一般情况一维数组 就简称为数组
## 数组的申明
### 变量类型[] 数组名; // 只是申明了数组,但是没有开辟内存空间
// 变量类型 可以使我们学过的 或者是没学过的变量类型
int[] arr1;
### 变量类型[] 数组名 = new 变量类型[数组的长度];
int[] arr2 = new int[5];
### 变量类型[] 数组名 = new 变量类型[数组长度]{内容1, 内容2, 内容3...}
int[] arr3 = new int[5]{1, 2, 3, 4, 5} // 必须填写和数组长度相等的内容
### 变量类型[] 数组名 = new 变量类型[]{内容1, 内容2, 内容3...}
int[] arr4 = new int[]{1, 2, 3, 4, 5} // 可变长度填写内容
### 变量类型[] 数组名 = {内容1, 内容2, 内容3...}
int[] arr4 = {1, 2, 3, 4, 5} // 可变长度填写内容
## 数组的使用
int arr = [1, 2, 3]
### 1 数组的长度
arr.Length;
### 2 获取数组中的元素
arr[0]
### 3 修改数组中的元素
arr[0] = 3;
### 4 遍历数组
for(int i = 0; i < arr.Length; i++)
{
arr[i]
}
### 5 增加数组的元素
数组初始化以后 是不能够 直接添加新元素的
int[] arr2 = new int[6];
// 搬家
for(int i = 0; i < arr2.Length; i++)
{
arr2[i] = arr[i];
}
arr = arr2;
### 6 删除数组的元素
数组初始化以后 是不能够 直接删除新元素的
int[] arr3 = new int[2];
for(int i = 0; i < arr3.Length; i++)
{
arr3[i] = arr[i];
}
arr = arr3;
### 7 查找数组中的元素
int a = 3;
for(int i = 0; i < arr.Length; i++)
{
if( a == arr[i])
{
break;
}
}
## 练习题
### 1
请创建一个一维数组并赋值,让其值与下标一样,长度为100
```
int[] arr = new int[100];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = i;
Console.WriteLine(arr[i]);
}
```
### 2
创建另一个数组B,让数组A中的每个元素的值乘以2存入到数组B中
```
int[] arr = new int[100];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = i;
Console.WriteLine(arr[i]);
}
int[] arr2 = new int[100];
for (int i = 0; i < arr2.Length; i++)
{
arr2[i] = arr[i] * 2;
Console.WriteLine(arr2[i]);
}
```
### 3
随机(0~100)生成1个长度为10的整数数组
```
int[] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr[i] = r.Next(0,10);
Console.WriteLine(arr[i]);
}
```
### 4
从一个整数数组中找出最大值、最小值、总合、平均值
(可以使用随机数1~100)
```
int[] arr = new int[100];
Random r = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr[i] = r.Next(1,100);
Console.WriteLine(arr[i]);
}
int max = 0, min = 100, average = 0, sum = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
if (arr[i] < min)
{
min = arr[i];
}
sum += arr[i];
}
average = sum / arr.Length;
Console.WriteLine("max: {0}, min: {1}, average: {2}, sum: {3}",
max, min, average, sum);
```
### 5
交换数组中的第一个和最后一个、第二个和倒数第二个,依次类推,把数组进行反转并打印
```
int[] arr = new int[10];
int temp;
Random r = new Random();
for (int i = 0; i < arr.Length; i++)
{
arr[i] = r.Next(1,100);
Console.Write(arr[i] + " ");
}
Console.Write("\n");
for (int i = 0; i < arr.Length / 2; i++)
{
temp = arr[i];
arr[i] = arr[arr.Length - i - 1];
arr[arr.Length - i - 1] = temp;
}
```
### 6
将一个整数数组的每一个元素进行如下的处理:
如果元素是正数则将这个位置的元素值加1;
如果元素是负数则将这个位置的元素值减1;
如果元素是0,则不变
```
int[] arr = new int[10] { -1, 2, 3, 4, -6, 12, -88, 21, -287, 0 };
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] != 0)
{
arr[i] = arr[i] > 0 ? arr[i] + 1 : arr[i] - 1;
}
}
```
### 7
定义一个有10个元素的数组,使用for循环,输入10名同学的数学成绩,将成绩依次存入数组,然后分别求出最高分和最低分,并且求出10名同学的数学平均成绩
```
int[] arr = new int[10];
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine("请输入学生的数学成绩:");
arr[i] = int.Parse(Console.ReadLine());
}
int max = 0, min = 100, average = 0, sum = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
if (arr[i] < min)
{
min = arr[i];
}
sum += arr[i];
}
average = sum / arr.Length;
Console.WriteLine("max: {0}, min: {1}, average: {2}, sum: {3}",
max, min, average, sum);
```
### 8
请声明一个string类型的数组 (长度为25)(该数组中存储着符号),通过遍历数组的方式取出其中存储的符号打印出以下效果
```
string[] arr = new string[25];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = i % 2 == 0 ? "◼︎" : "◻︎";
}
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i]);
if ((i + 1) % 5 == 0 && i != 0)
{
Console.WriteLine("");
}
}
```
## 一、基本概念
### 枚举是什么
// 枚举是比较特别的存在,他是一个被命名的整型常量的集合,一般用它来表示 状态 类型 等等
// 注意⚠️ 申明枚举 和申明枚举变量 是两个概念
### 申明枚举 和 申明枚举变量
// 申明枚举 相当于是 创建一个自定义的枚举类型
// 申明枚举变量 使用申明的自定义枚举类型 创建一个枚举变量
### 申明枚举语法
enum E_自定义枚举名
{
自定义枚举项名字1,// 枚举中包裹的整型常量,默认值是0,下面会依次累加
自定义枚举项名字2 = 5,
自定义枚举项名字3,
自定义枚举项名字4,
}
## 二、在哪里申明枚举
// 1. namespace语句块中申明
// 2. class语句块中,struct语句块中
// 3. 不能在函数语句块中申明!!!
## 三、枚举的使用
// 申明枚举变量
// 自定义的枚举类型 变量名 = 默认值;
enum E_PlayerType
{
Main,
Other,
}
E_PlayerType playerType = E_PlayerType.Main;
if (playerType == E_PlayerType.Main)
{
Console.WriteLine("......");
}
// 枚举和switch是天生一对
## 四、枚举的类型转换
### 1. 枚举和int互转
int i = (int)playerType;
### 2. 枚举和string互转
string str = playerType.ToString(); // Main
// string转成枚举,比较复杂不推荐使用
// parse后 第一个参数: 你要转为的是哪个枚举类型,第二个参数:用于转换的对应枚举项的字符串
// 转换完毕后,是一个通用的类型 我们需要使用括号强转成我们想要的目标枚举类型
playerType = (E_PlayerType)Enum.Parse(typeof(E_PlayerType), "Main")
## 五、枚举的使用
// 在游戏开发中,对象很多时候会有许多的状态
// 比如玩家 有一个动作状态 我们需要用一个变量或者表示 来表示当前玩家处于的哪种状态
// 1 行走 2 待机 3 跑步 ...
## 练习题
### 1
定义QQ状态的枚举,并提示用户选择一个在线状态,我们接受输入的数字,并将其转换成枚举类型
```
using System;
namespace Enum相关
{
enum E_QQ
{
online,
outline,
away,
}
class Program
{
static void Main(string[] args)
{
E_QQ userStatus = E_QQ.online;
Console.Write("请输入您的在线状态(0 在线 1 不在线 2 离开一会儿):");
string userStatusStr = Console.ReadLine();
userStatus = (E_QQ)Enum.Parse(typeof(E_QQ), userStatusStr);
Console.WriteLine(userStatus);
}
}
}
```
### 2
用户去星巴克买咖啡,分为中杯(35元),大杯(40元),超大杯(43元),请用户选择要购买的类型,用户选择后,打印:您购买了xxx咖啡,花费了xx元
例如:你购买了中杯咖啡,花费了35元
```
using System;
namespace Enum相关
{
enum E_coffee
{
中杯 = 35,
大杯 = 40,
超大杯 = 45,
}
class Program
{
static void Main(string[] args)
{
E_coffee userCoffee;
Console.Write("请输入您需要的咖啡类型:");
string userCoffeeStr = Console.ReadLine();
userCoffee = (E_coffee)Enum.Parse(typeof(E_coffee), userCoffeeStr);
Console.WriteLine("您选择的咖啡是:{0}, 花费了:{1}", userCoffee.ToString(), (int)userCoffee);
}
}
}
```
### 3
请用户选择英雄性别与英雄职业,最后打印英雄的基本属性(攻击力,防御力,技能)
性别:
男(攻击力+50,防御力+100)
女(攻击力+150,防御力+20)
职业:
战士(攻击力+20,防御力+100,技能:冲锋)
猎人(攻击力+120,防御力+30,技能:假死)
法师(攻击力+200,防御力+10,技能:奥术冲击)
举例打印:你选择了“女性法师”,攻击力:350,防御力:30,职业技能:奥术冲击
```
using System;
namespace Enum相关
{
enum E_sex
{
women,
man,
}
enum E_Job
{
warrior,
hunter,
master
}
class Program
{
static void Main(string[] args)
{
int userAtk = 0;
int userDf = 0;
string sexStr = "";
string jobStr = "";
string userSkill = "";
E_sex userSex;
Console.Write("冒险者,请输入您的性别(0 女性 1 男性):");
string userSexStr = Console.ReadLine();
userSex = (E_sex)Enum.Parse(typeof(E_sex), userSexStr);
E_Job userJob;
Console.Write("冒险者,请输入您的职业(0 战士 1 猎人 2 法师):");
string userJobStr = Console.ReadLine();
userJob = (E_Job)Enum.Parse(typeof(E_Job), userJobStr);
switch (userSex)
{
case E_sex.women:
userAtk += 150;
userDf += 20;
sexStr = "女性";
break;
case E_sex.man:
userAtk += 50;
userDf += 100;
sexStr = "男性";
break;
}
switch (userJob)
{
case E_Job.warrior:
userAtk += 20;
userDf += 100;
userSkill = "冲锋";
jobStr = "战士";
break;
case E_Job.hunter:
userAtk += 120;
userDf += 30;
userSkill = "假死";
jobStr = "猎人";
break;
case E_Job.master:
userAtk += 200;
userDf += 10;
userSkill = "奥术冲击";
jobStr = "法师";
break;
}
Console.WriteLine("你选择了“{0}{1}”,攻击力:{2},防御力:{3},职业技能:{4}",
sexStr, jobStr, userAtk, userDf, userSkill);
}
}
}
```
递归函数
知识点一:基本概念
就是让函数自己调用自己
一个正确的递归函数
1.必须有结束调用的条件
2.用于条件判断的这个条件 必须改变,能够达到停止的目的
递归函数应用较少
主要应用于面试
函数重载
知识点一:基本概念
在同一语句块中(class或者struct)中
函数(方法)名相同
参数数量不同
或者
参数数量相同,但参数的类型类型顺序不同
作用
1、命名一组功能相似的函数,减少函数数名的数量,避免命名空间的污染
2、提升程序可读性
知识点二:实例
注意:
1、重载和返回值无关,纸盒参数类型,个数,顺序有关
2.调用时,程序会自己根据传入的函数类型判断使用哪一个重载
参数数量不同
static int CalcSum(int a,int b,int c)
{
return a + b + c;
}
一维数组
知识点二
数组是存储一组相同类型数据的集合
数组分为 一维,多维,交错数组
一般情况 一维数组 就简称为数组
知识点二 数组的申明
变量类型[] 数组名 //知识申明了一个数组 但是没有开放
变量类型 可以是我们学过的 或者 没学过的所有变量类型
int[] arr1 ;
变量类型[] 数组名 = new 变量类型[数组的长度];
int[] arr2 = new int[5];//这种方式相当于开了5个房间 但是房间里面的int 值 默认为0
变量类型[] 数组名 = new 变量类型[数组的长度]{ 内容1,内容2,内容3...............};
int[] arr3 = new int[5]{1,23,4,5 };
变量类型[] arr2 = new int{}
变量类型[] 数组名 = { 内容1,内容2,内容3};
int[] arr5 = {1,3,4,5,6}; 后面的内容就决定了 数组的长度 房间数
知识点三 数组的使用
1.数组长度
数组变量名.Length
2.获取数组中的元素
通过 序偶因下标 去 获得
数组中下标和索引 它们是从0开始的
通过索引下标去 获得数据中某一个元素的值
一定要注意
不能越界 ,数组的房间号 范围 是 0-length-1
3.修改数组中的元素
array[0] = 99;
4.遍历数组
5.增加数组元素
6.删除数组元素
7.查找数组中的元素
枚举
知识点1 基本概念
1、枚举是什么
枚举是一个比较特殊的存在
它时一个被命名的整形常量的集合
一般用它来表示状态 类型 等等
2、申明枚举 和 申明枚举变量
注意:申明枚举 和 申明枚举变量时两个概念
申明枚举:相当于是创建一个自定义枚举类型
申明枚举变量: 使用申明的自定义枚举类型 创建一个枚举变量
3、申明枚举语法
枚举名以 E或者E_开头,作为我们命名的规范
enum E_自定义枚举名
枚举里包裹的整形常量 第一个默认值是0 下面会一次累加
{
自定义枚举项名字 = 5,
自定义枚举项名字1,
自定义枚举项名字2,
}
知识点二 在哪里生命枚举
1.namespace 语句块中 常用
2.chass语句块中 struct语句块中
注意:枚举不能在函数语句块中申明
enum E_MonsterType
{
Normal, //0
Boss, //1
}
enum E_PlayerType
{
Main,
Other
}
知识点三 枚举的使用
//申明枚举变量
E_PlayerType playerType = E_PlayerType.Main;
if (playerType == E_playerType.Main)
{
}
else if (player Type == E_PlayerType.Other )
{
}
枚举和switch是天生一对,枚举一般配合条件分支进行的
知识点四 枚举的类型转换
1.枚举和int互转
int i = (int)playerType;
2.枚举和string相互转换
string str = playerType.Tostring();
把string 转成枚举
Parse 后第一个参数 :你要转为哪一个枚举类型
第二个参数 :用于转换的对应的枚举项的字符串
转换完毕后 是一个通用的类型 我们需要用括号强转成我们想要目标枚举类型
playerType = Enum.Parse(typeof(E_playerType),"Other");
知识点五 枚举的作用
1.在游戏开发中,对象很多的时候 会有许多的状态
比如玩家有一个对坐状态 我们需要一个变量 或者标识 来表示当前玩家处于是哪种状态
综合考虑 可能会使用int 来表示他的状态
1 行走 2待机 3跑步 4跳跃 等等
枚举可以帮助我们 清晰地分清楚状态的含义
游戏场景循环
检测输入,扔色子的逻辑,绘制地图,绘制玩家,判断是否要结束游戏(电脑和玩家,一共做两次)
创建扔色子函数
返回值用bool,传一个结果到外面,判断游戏结束,默认没有结束
扔骰子的目的是改变我那家或者电脑的位置,计算位置的变化
扔骰子之前判断玩家是否处于暂停状态