1,复杂数据类型概述。
前景提要
数据(变量)类型(几个字节,存储数位)
无符号变量:byte、ushort、uint、ulong
有符号变量:sbyte,short,int,long
浮点数:float,double,decimal
特殊类型:bool、char、string
复杂数据(变量)类型特点
1.数据集合
一般是多个数据(变量)集合在一起构成的数据
2.自定义
一般可以自己取名字,可以自定义的数据(变量)
例子:
枚举:整形常量的集合,可以自定义
数组:任意变量类型顺序存储的数据
结构体:任意变量的数据集合,可以自定义
111.枚举:
1.枚举是什么:枚举是一个比较特别的存在,它是一个被命名的整形常量的集合。一般用它来表示 状态 类型 等等
2.声明枚举 和 申明枚举变量::注意:串明枚举 和 声明枚举变量是两个概念!
声明枚举:相当于是 创建一个自定义的枚举类型
声明枚举变量:使用声明的自定义枚举类型 创建一个枚举变量
枚举关键字:enum
3.声明枚举语法
枚举名命名规范: 以E或者E 开头
例子:
enum E_ 自定义枚举名
{
白定义枚举项名字,//枚举中包裹的 整形常量 第一个默认值是。 下面会依次累加
自定义枚举项名字1,//1
自定义枚举项名字2,//2
}
22,在哪里声明
在namspace 语句块(常用),在class语句块中, struct语句块中。
注意:枚举不在函数语句中声明
例子:
enum E_PlayerType
{
Main,//1
other,//2
}
33,枚举的使用
声明枚举是在方法里面的:自定义枚举类型 变量名 = 默认值;(自定义的枚举类型。枚举项)
E PlayerType playerType =E PlayerType.Main;
if( playerType ==E_PlayerType.Main )
{
Console.WriteLine("主玩家逻辑");
}
else if(playerType ==E PlayerType.0ther)
{
Console.WriteLine("其它玩家逻辑");
}
//枚举和switch搭配使用
E MonsterType monsterType =E MonsterType.Boss;
switch(monsterType)
{
case E MonsterType.Normal:
break;
case E MonsterType.Boss:
break;
default:
break;
}
44,枚举的类型转换
//1.枚举和int互转(括号强转)
int i=(int)playerType;
Console.WriteLine(i);
//int 转枚举
playerType = 0;
string str = playerType.Tostring();
Console.WriteLine(str);
把string转成枚举呢?Parse后 第一个参数 :你要转的是哪个 枚举类型, 第二个参数:用于转换的对应枚举项的字符串。。转换完毕后 是一个通用的类型 我们需要用括号强转成我们想要的目标枚举类型。
看习题
55,枚举的作用
1,在游戏开发中,对象很多时候 会有许多的状态:比如玩家 有一个动作状态 我们需要用一个变量或者标识 来表示当前玩家处于的是哪种状态
2,综合考虑 可能会使用 int 来表示他的状态:1 行走 2 待机 3 跑步 4 跳跃。。。。。。。
3,枚举可以帮助我们 清晰的分清楚状态的含义
.数组
11,一维数组
数组是存储一组相同类型数据的集合:数组分为 一维、多维、交错数组。一般情况 一维数组 就简称为 数组。
数组的声明:变量类型[]数组名;//只是声明了一个数组
01 变量类型 所有变量类型都可以int[] arrls;或者 int a = 10;
02变量类型[]数组名 = new 变量类型[数组的长度]; int[]arr2 = new int[5];//这种方式 相当于开了5个房间 但是房间里面的int值 默认为8
03变量类型[]数组名 = new 变量类型[数组的长度]{内容1,内容2,内容3,} int[]arr3 =new int[5]{1,2,3,4,5 };
04变量类型[]数组名 = new 变量类型[]{内容1,内容2,内容3.} int[] arr4 = new int[]{ 1,2,3,4,5,6,7,8,9};//后面的内容就决定了 数组的长度"房间数"
05变量类型[]数组名 ={内容1,内容2,内容3,...}; int[] arr5 ={ 1,3,4,5,6};
数组的使用
int[]array ={1,2,3,4,5 };
1.数组的长度.Length
2.获取数组中的元素
数组中的下标和索引 他们是从@开始的...。通过 索引下标去 获得数组中某一个元素的值时
一定注意:不能越界 数组的房间号 范围 是0 ~ Length-1
Console.WriteLine(array[0]);
Console.WriteLine(array[2]);
Console.WriteLine(array[4]);
3.修改数组中的元素
array[0]= 99;
Console.WriteLine(array[0]);
4.遍历数组 通过循环 快速获取数组中的每一个元素
Console.WriteLine("*******************")
for(int i=0;i< array.Length; i++)
{
Console.WriteLine(array[i]);
}
5.增加数组的元素
数组初始化以后 是不能够 直接添加新的元素的::::
int[] array2 = new int[6];
for(int i=0;i< array.Length; i++)
{
array2[i]= array[i];
array = array2;
}
for(int i=0;i< array.Length; i++)
{
Console.WriteLine(array[i]);
}
array[5]= 999;
Console.WriteLine("*******")
6.删除数组的元素
数组初始化以后 是不能够 直接删除元素的
int[] array3 = new int[5];
for(int i=0;i< array3.Length; i++)
{
array3[i]= array[i];
}
array = array3;
Console.WriteLine(array.Length);
7.查找数组中的元素
// 要查找 元素在哪个位置
// 只有通过遍历才能确定 数组中 是否存储了一个日标元素
例子:
int a = 3;
for(int i=0;i<array.Length; i++)
{
if( a == array[i])
Console.WriteLine("和a相等的元素在{0}索引位置",i);
break;
}
}
总结
1.概念:同一变量类型的数据集合
2.一定要掌握的知识:中明,遍历,增删查改
3.所有的变量类型都可以申明为 数组
4.她是用来批量存储游戏中的同一类型对象的 容器 比如 所有的怪物 所有玩家
二维数组
概念:二维数组 是使用两个下标(索引)来确定元素的数组,两个下标可以理解成 行标 和 列标。比如矩阵
例子:
可以用二维数组 in+[2,3]表示。好比 两行 三列的数据集合
声明:
01量类型[,]二维数组变量名;
int[ , ]arr;//申明过后 会在后面进行初始化
02变量类型[ , ]二维数组变量名 = new 变量类型[行,列];
int[,] arr2 = new int[3, 3];
03变量类型[,]二维数组变量名 = new 变量类型[行,列]
int[,]arr3 =new int[3,3]{{1,2,3 },
{4,5,6}
{7,8,9 }};
04变量类型[,]二维数组变量名 = new 变量类型[,]
int[,]arr4 = new int[,]{{1,2,3 },
{4,5,6 },
{7,8,9}};
05变量类型[,]二维数组变量名 ={{0行内容1,0行内容2,0行内容3.
int[,]arr5 ={{1,2,3 },
{4,5,6},
{7,8,9}};
交错数组
1.交错数组 是 数组的数组,每个维度的数量可以不同.。注意:二维数组的每行的列数相同,交错数组每行的列数可能不同
01变量类型[][]交错数组名;
int[][] arrls
02变量类型[[] 交错数组名 = new
03变量类型[行数][];
int[][] arr2 = new int[3][];
04变量类型[][] 交错数组名 = new 变量类型[行数][]{ 一维数组1,一维数组2,... };
int[][] arr3 = new int[3][]
{
new int[]{1,2,3 },
new int[]{1,2,3 },
new int[] { 1,2.3 }};
}
使用:
int[][] array ={ new int[]{ 1,2,3},
new int[]{ 4,5} };
1.数组的长度
01 行
Console.WriteLine(array.GetLength(0));
02 得到某一行的列数
Console.WriteLine(array[0].Length);
2.获取交错数组中的元素
Console.WriteLine(array[0][1]);
3.修改交错数组中的元素
4.遍历交错数组
for(int i=0;i<array.GetLength(0);i++)
{
for(int j=0;j< array[i].Length; j++)
{
Console.Write(array[i][j]+"");
}
Console.WriteLine();
}
值类型与引用类型
变量类型的复习
01无符号整形
byte b = 1;
ushort us = 1;
uint yi = 1;
ulong ul = 1;
02有符号整形
sbyte sb =1;
short s.= 1;
int i = 1;
long 1.= 1;
03浮点数
float f = 1f;
double d = 1.1;
decimal de =1.1m;
04特殊类型
bool bo = true;
char c.= 'A';
string str ="strs"
05复杂数据类型
enum 枚举
数组(一维,二维,交错)
值类型
int a = 10;
01引用类型
int[]arr = new int[]{1,2,3,4 };
02中明了一个b让其等于之前的a
int b = a;
03申明了一个arr2让其等于之前的arr
int[] arr2 = arr;
Console.WriteLine("a={0},b={1}",a, b);
Console.WriteLine("arr[e]={0},arr2[0]={1}",arr[0],arr2[0]);
b= 20;
arr2[0]= 5;
Console.WriteLine("修改了b和arr2[0]之后");
Console.WriteLine("a={0},b={1}",a, b);
Console.WriteLine("arr[0]={0},arr2[0]={1}",arr[0],arr2[0]);
值类型 在相互赋值时 把内容拷贝给了对方 它变我不变
引用类型的相互赋值 是 让两者指向同一个值 它变我也变
2.为什么有以上区别
值类型 和 引用类型 存储在的 内存区域 是不同的 存储方式是不同的,所以就造成了 他们在使用上的区别:
值类型存储在 栈空间- 系统分配,自动回收,小而快
引用类型 存储在 堆空间 - 手动申请和释放,大而慢
string的 它变我不变
因为string是引用类型 :string非常的特殊 它具备 值类型的特征 它变我不变
string 虽然方便 但是有一个小缺点 就是频繁的 改变string 更新赋值
会产生 内存垃圾
函数
函数(方法)本质是一块具有名称的代码块,可以使用函数(方法)的名称来执行该代码块。函数(方法)是封装代码进行重复使用的一种机制
函数(方法)的主要作用1.封装代码2,提升代码复用率(少写点代码)3.抽象行为
函数写在哪里:1.class语句块中2.struct语句块中
基本语法
1 2 3 4
static 返回类型 函数名(参数类型 参数名1,参数类型 参数名2,
函数的代码逻辑
函数的代码逻辑:
函数的代码逻辑;
5
return 返回值;(如果有返回类型才返回)
解释:
1.关于static: 类和结构体之前 都是必须写的
2-1.关于返回类型 引出一个新的关键字void(表示没有返回值)
2-2.返回类型 可以写任意的变量类型,14种变量类型 + 复杂数据类型(数组、枚举、结构体、类class)
3.关于函数名 使用帕斯卡命名法命名myName(驼峰命名法)MyName(帕斯卡命名法)
4-1.参数不是必须的,可以有0~n个参数 参数的类型也是可以是任意类型的 14种变量类型 + 复杂数据类型(数组、枚举、结构体、类class)多个参数的时候 需要用 逗号隔开
4-2.参数名 驼峰命名法
5.当返回值类型不为void时 必须通过新的关键词 return返回对应类型的内容 (注意:即使是void也可以选择性使用return)
函数的实际运用
1.无参无返回值的数
static void sayHellow()
{
Console.WriteLine("你好世界");
}
2.有参无返回值函数
1 2 3 4
static void SayYourName(string name)
{
Console.WriteLine("你的名字是:{0}",name);
}
// return;省略了
3.无参有返回值函数
static stringWhatYourName()
{
return"填丫丫 ";
}
4.有参有返回值函数
static int Sum(int a, int b)
{
//int c= a+ b;
//return c;
return a+b;
}
5.有参有多返回值函数
传入两个数 然后计算两个数的和 以及他们两的平均数 得出结果返回出来
函数的返回值 一定是一个类型 只能是一个内容
static int[] calc(int a, int b)
{
int sum = a + b;
int avg =sum /2;
//int[]arr ={ sum, avg };
//return arr;
return new int[l{sum, avg};
}
关于return
即使函数没有返回值,我们也可以使用return,
return:可以直接不执行之后的代码,直接返回到函数外部.02 可以提前结束函数逻辑,程序是线性执行了,从上到下。
ref和out
**1,ref和out:**它们可以解决 在函数内部改变外部传入的内容 里面变了外面也要变
2.ref和out的使用
函数参数的修饰符。当传入的值类型参数在内部修改时 或者引用类型参数在内部重新申明时,外部的值会发生变化。
例子:
static void changeValueRef(ref int value)
{
value = 3;
}
static void changeArrayRef( ref int[] arr )
{
arr = new int[]{100,200,300 };
}
ref和out的区别
1.ref传入的变量必须初始化 out不用
2.out传入的变量必须在内部赋值 ref不用
ref传入的变量必须初始化 但是在内部 可改可不改
out传入的变量不用初始化 但是在内部 必须修改该值(必须赋值A
变长参数
变长参数关键字 params
举例 函数要计算 n个整数的和
//static int Sum(int a,int b。。。。。。。)
//变长参数关键字 params
2个引用
static int Sum(params int[] arr)
{
int sum =0;
for(int i=0;i< arr.Length; i++)
{
sum += arr[i];
return sum;
}
}
//params int[]意味着可以传入n个int参数 n可以等于8 传入的参数会存在arr数组中
注意:
1.params关键字后面必为数组。
2.数组的类型可以是任意的类型
3.函数参数可以有 别的参数和 params关键字修饰的参数
4.函数参数中只能最多出现一个params关键字 并且一定是在最后一组参数 前面可以有n个其它参数
示例:
static void Eat( string name, int a, int b, params string[] things.
{
}
参数默认值
有参数默认值的参数 一般称为可选参数
作用是: 当调用函数时可以不传入参数,不传就会使用默认值作为参数的值
static void Speak(string sjtr ="我没什么话可说")
{
Console.WriteLine(str);
}
注意:
1.支持多参数默认值 每个参数都可以有默认值
2.如果要混用 可选参数 必须写在 普通参数后面
例子:
static void Speak( string a,string sjtr ="我没什么话可说",string sttr ="我没什么话可说")
{
Console.WriteLine(str);
}
函数重载
基本概念
概念:同一个语句块中,函数名相同,参数数量、类型、顺序不同的函数 就称为我们的重载函数
注意: 和返回值无关
作用: 一般用来处理不同参数的同一类型的逻辑处理。
汪意:1.重载和返回值类型无关,只和参数类型,个数,顺序有关 2.调用时 程序会自己根据传入的参数类型判断使用哪一个重载参数数量不同
static int CalcSum(int a, int b)
{
return a + b;
}
//参数数量不同
static int CalcSum(int a,int b,int c)
{
return a +b+c;
}
//数量相同 类型不同
static int CalcSum(int a,int b)
{
return a +b;
}
//数量相同 类型不同
static float CalcSum(int a, float f)
{
return a + f;
}
//数量相同 顺序不同
static float CalcSum(float f, int a)
{
return f+a;
}
ref 和 out
static float CalcSum(ref float f, int a)
{
return f+ a;
}
static float calcSum(int a, int b, params int[] arr)
{
return 1;
}
static void Main(string[] args)
{
Console.WriteLine("函数重载");
Calcsum(1,2);
Calcsum(1.1f,2);
Calcsum(1,2,3);
Calcsum(1,1.2f);
}
递归函数
基本概念: 递归函数就是让函数自己调用自己
一个正确的递归函数 1.必须有结束调用的条件 2.用于条件判断的 这个条件 必须改变 能够达到停止的目的
实例:
//用递归函数打印出 0到10
//递归函数 就是自己调用自己
static void Main(string[] args)
{
// 正常情况
Fun(1); // 打印1-10
// 边界情况
Fun(10); // 只打印10
// 无效输入
Fun(0); // 显示错误信息
Fun(-5); // 显示错误信息
}
static void Fun(int a)
{
// 参数验证
if (a <= 0)
{
Console.WriteLine("输入参数必须大于0");
return;
}
// 递归终止条件
if (a > 10)
{
return;
}
// 打印当前值
Console.WriteLine(a);
// 递归调用
Fun(a + 1);
}
结构体
基本概念
结构体是一种自定义变量类型 类似枚举需要自己定义,它是数据和函数的集合。在结构体中 可以申明各种变量和方法。
作用:用来表现存在关系的数据集合 比如用结构体表现学生 动物 人类等等
基本语法
1.结构体一般写在 namespace语句块中
2.结构体关键字 struct
struct 自定义结构体名
{
第一部分
// 变量
第二部分
// 构造函数(可选)
第三部分
// 函数
}
实例
struct
{
函数方法
//表现这个数据结构的行为
//注意 在结构体中的方法 目前不需要加static关键字
0 个引用
void speak()
{
//函数中可以直接使用结构体内部申明的变量
Console.WriteLine("我的名字是{0},我今年{1}岁",name,age);
}
//可以根据需求 写无数个函数的
}
结构体的构造函数
/基本概念
//1.没有返回值
//2.函数名必须和结构体名相同
//3.必须有参数
//4.如果申明了构造函数 那么必须在其中对所有变量数据初始化
冒泡排序
排序的基本概念
//排序是计算机内经常进行的一种操作,其目的是将一组"无序"的记录序列调整为"有序"的记录序列
//常用的排序例子
//871542639
// 把上面的这个无序序列 变为 有序(升序或降序)序列的过程
//123456789(升)
//987654321(降序)
//在程序中 序列一般 存储在数组当中
//所以 排序往往是对 数组进行排序
int[]arr =hew int[]{8,7,1,514,2,6,3,9,};
//把数组里面的内容变为有序的
冒泡排序基本原理
//871542639
两两相邻
不停比较
不停交换
比较n轮
代码实现
示例:
//第一步 如何比较数组中两两相邻的数
//8,7,1,5,4,2,6,3,9
//从头开始
//第n个数和第n+1个数 比较
for(intn=0;n<arr.Length-1;n++)
{
//如果 第n个数 比第n+1个数 大 他们就要交换位置
if( arr[n]>arr[n + 1])
{
// 第二步 交换位置
// 中间商不赚差价
int temp = arr[n];
arr[n]= arr[n +1];
arr[n +1]= temp;
}
}
声明的数组:(粉色最终,红色第二步)
int[]arr =new int[]{8,7,1,5,4,2,6,3,9,};
int[] arr = new int[] { 8, 7, 1, 5,7,2,6,3, 9, };
//有几个数 就比较多少轮 m
for (int m = 0; m<arr.Length; m++)
{
bool isSort = false;
// 一次循环 就要比较一轮//m是减去m轮,剩下的伦去比较
for (int n = 0; n < arr.Length - m; n++)
{
//如果 第n个数 比第n+1个数 大 他们就要交换位置
if (arr[n] > arr[n + 1])
{
isSort = true;
// 第二步 交换位置
// 中间数
int temp = arr[n];
arr[n] = arr[n + 1];
arr[n + 1] = temp;
}
}
if (!isSort)
{
break;
}
}
如果一轮结束后,issort标识是false就意味着已经是最终的序列了,不需要再判断交换了。
issort标识是为了能够使得不需要比较的可以不移动(也就是最后几个以确定的不需要再去比较)
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine(arr[i]);
}
总结
基本概念:两两相邻,不停比较,不停交换,比较m轮,套路写法,两层循环,外层轮数内层比较,两值比较,满足交换
如果优化 1.比过不比2.加入boo1
选择排序:
选择排序基本原理//87 1 5 4
新建中间商
依次比较
找出极值(最大或最小)
放入目标位置
比较n轮
语法
internal class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 0, 5 };
//05 比较m伦
for (int m = 0; m < arr.Length; m++)
{
//声明中间值来记录索引
//每一轮开始默认第一个都是极值
int index = 0;
//02依次比较:-m是:排除上一轮已经放好的数
for (int n = 0;n < arr.Length-m ; n++)
{
//03 找到最大值
if (arr[index] < arr[n])
{
index = n;
}
}
//04放入目标位置: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;
}
}
//打印值
for(int i = 0; i < arr.Length; i++)
{
Console.WriteLine(arr[i]+" ");
}
//总结
//基本概念:新建中间商;依次比较
找出极值
放入目标位置
比较n轮
套路写法
两层循环
外层轮数
内层寻找
初始索引
记录极值
内存循环外交换
}
}