c# 课堂总结7--函数
函数:
数据类型-变量类型-运算符号表达式-语句(顺序,分支,循环)-数字
程序里的函数:能完成一个相对独立功能的代码块。
数学里的函数:高度抽象。
函数四要素:函数名,输入(参数),输出(返回值类型),加工(函数体)
函数定义:
[static]返回类型 函数名(输入参数列表)
{
//函数体-加工
}
函数调用:
[数据类型 变量名]=函数(参数);
函数名(参数);---用于无返回类型的函数
数据类型 变量=函数名(参数);---用于有返回类型的函数
1.参数匹配
在调用函数时,调用的参数和函数定义的参数保持一对待:个数,类型,对应。
形参:形式参数。--函数定义的参数。
实参:实际参数。--函数调用的参数。
实参、形参传值的规律--传址,传值。
传值:鉴于整型、浮点、bool、char这几种内建函数传递参数的时候,默认都是传值。
传值是把实参做一个副本(copy)传递给形参。
m=30;
Add(m);
static void Add(int a)
{
a+=20;
}
传址:默认情况下,数组就是传地址。字符串也是传地址。
对于内建的整型、浮点、bool、char这些类型,如果要变成传址的话,需要在前面加ref
m=30;
Add(ref m);
static void Add(ref int a)
{
a+=20;
}
对于传值和传址大家要记住:
1.什么是传值,什么传址?这个要分清楚。
2.默认情况下,哪些类型传值?哪些类型传址?
3.对于默认传值的类型,如何让他们变为传址?ref
以后为了防止因为传值、传址引起的错误,建议采用返回值的形式,明确返回的数据。
例题部分
1 eg.1 传值的方法 2 static void Main(string[] args) 3 { 4 int m = 30; 5 Console.WriteLine("Main函数第一次打印:"+m);//30 6 Add(m); 7 Console.WriteLine("Main函数第二次打印:" + m);//30 8 } 9 static void Add(int a) 10 { 11 Console.WriteLine("Add函数第一次打印:"+a);//30 12 a += 20; 13 Console.WriteLine("Add函数第二次打印:"+a);//50 14 } 15 16 17 eg.2 传址方式,加ref 18 static void Mainb(string[] args) 19 { 20 int m = 30; 21 Console.WriteLine("Main函数第一次打印:" + m);//30 22 Add1( m); 23 Console.WriteLine("Main函数第二次打印:" + m);//30 24 Console.WriteLine("Main函数第三次打印:" + m);//30 25 Add2(ref m); 26 Console.WriteLine("Main函数第四次打印:" + m);//50 27 } 28 29 static void Add1(int a) 30 { 31 Console.WriteLine("Add1传值函数第一次打印:" + a);//30 32 a += 20; 33 Console.WriteLine("Add1传值函数第二次打印:" + a);//50 34 } 35 36 static void Add2(ref int a) 37 { 38 Console.WriteLine("Add2传址函数第一次打印:" + a);//30 39 a += 20; 40 Console.WriteLine("Add2传址函数第二次打印:" + a);//50 41 } 42 43 eg.3 传址与传值 数组名 传址,数组元素传值。 44 static void Main1(string[] args) 45 { 46 int[] m = new int[4] {3,5,7,9 }; 47 48 //打印原值 49 foreach (int a in m) 50 { 51 Console.Write(a+"\t"); 52 } 53 54 //调用函数,传递整个数组 55 Add(m);//传得是数组名,传的是地址。 56 57 Add9(m[2]);//传得是数组的某个元素,是传值。 58 //打印改变后的值 59 foreach (int a in m) 60 { 61 Console.Write(a+"\t"); 62 } 63 } 64 65 static void Add9(int a) 66 { 67 Console.WriteLine("Add9被调用了,在Add9中把传进来的" + a + "变成了" + a * 100); 68 a = a * 100; 69 } 70 71 static void Add(int[] b) 72 { 73 for (int i = 0; i < b.Length; i++) 74 { 75 b[i] *= 10; 76 } 77 }
2、函数重载?
在函数重载时,应包括函数签名的所有方面,例如,有两个不同的函数,他们分别值参数和引用参数。
static void ShowDouble(ref int val)
{
....
}
static void ShowDouble(int val)
{
....
}
选择使用哪个版本纯粹是根据是否包含ref关键字来确定的,下面的代码将调用引用版本:
ShowDouble(ref val);
下面的代码将调用值版本:
ShowDouble(val);
另外还要根据参数的个数来区分函数。
3、委托。
eg.1 对战改 函数
1 //人人对战 2 3 4 class class1 5 { 6 static void Mainmydemo5(string[] args) 7 { 8 string[] jn=new string[10];//return 与out 的区别 :out 返回值时,不用规定数组的大小,return返回值是,数组必须创建出多大的。eg买东西! 9 //int[] sh=new int[10]; 10 int[] sh; 11 jn = JiNeng(jn, out sh);//数组默认就是传址,不需要加ref,但有的时候不同 12 13 //string[] jn; 14 //int[] sh; 15 //JiNeng(out jn, out sh); 16 17 player p1=new player(); 18 player p2=new player(); 19 ShuRu(ref p1.name, ref p2.name); 20 21 //攻击方数据输出 22 p1 = PlayerPeiZhi(jn, sh, p1); 23 PlayerPeiZhiShuChu(p1); 24 25 //防守方数据输出 26 p2 = PlayerPeiZhi(jn, sh, p2); 27 PlayerPeiZhiShuChu(p2); 28 29 //战斗开始 30 Console.WriteLine("→→→→→→→→→"); 31 32 Console.WriteLine("请按空格键开始对战"); 33 ConsoleKeyInfo key = Console.ReadKey(); 34 Console.Clear(); 35 36 if (key.Key.ToString().ToLower() == "spacebar") 37 { 38 while (true) 39 { 40 #region 战斗开始 41 //攻击方攻击 42 ZhanDou(ref p1, ref p2); 43 44 Console.WriteLine(p1.name + "的血量为:" + p1.blood + "," + p2.name + "的血量为:" + p2.blood); 45 46 47 48 //退出循环的判断! 49 bool m = TuiChu(ref p1, ref p2); 50 if (m) 51 { 52 break; 53 } 54 else 55 { 56 57 } 58 59 60 //防守方攻击 61 ZhanDou(ref p2, ref p1); 62 63 Console.WriteLine(p1.name + "的血量为:" + p1.blood + "," + p2.name + "的血量为:" + p2.blood); 64 65 66 67 //退出循环的判断! 68 bool n = TuiChu(ref p1, ref p2); 69 if (n) 70 { 71 break; 72 } 73 else 74 { 75 76 } 77 #endregion 78 79 Thread.Sleep(2000); 80 } 81 } 82 } 83 84 85 86 /// <summary> 87 /// 输出玩家的配置 88 /// </summary> 89 /// <param name="t">形参 玩家</param> 90 private static void PlayerPeiZhiShuChu(player t) 91 { 92 player a = new player(); 93 a = t; 94 Console.WriteLine("攻击方的战斗力如下:"); 95 Console.WriteLine("姓名:" + a.name + ",血量:" + a.blood + ",攻击力:" + a.attack + ",防御力:" + a.defence + ",闪避力:" + a.shanbi); 96 Console.WriteLine("技能1为:{0},技能2为:{1},技能3为{2} 。", a.jineng[0], a.jineng[1], a.jineng[2]); 97 } 98 99 100 101 /// <summary> 102 /// 判断退出条件 103 /// </summary> 104 /// <param name="a">玩家1的信息</param> 105 /// <param name="b">玩家2的信息</param> 106 /// <returns>为 真 则退出,为 假 则继续。</returns> 107 private static bool TuiChu(ref player a, ref player b) 108 { 109 bool c; 110 if (b.blood == 0) 111 { 112 Console.WriteLine(a.name + "将" + b.name + "KO!"); 113 c = true; 114 //break; 115 } 116 else if (a.blood == 0) 117 { 118 Console.WriteLine(b.name + "将" + a.name + "KO!"); 119 c = true; 120 //break; 121 } 122 else if (a.blood == 0 && b.blood == 0) 123 { 124 Console.WriteLine("平局!"); 125 c = true; 126 //break; 127 } 128 else 129 { 130 c = false; 131 } 132 return c; 133 } 134 135 136 /// <summary> 137 /// 战斗开始 138 /// </summary> 139 /// <param name="p1">玩家1的信息</param> 140 /// <param name="p2">玩家2的信息</param> 141 private static void ZhanDou(ref player a, ref player b) 142 { 143 //普通攻击 144 Random m1 = new Random(); 145 //int a1 = m1.Next(3); 146 if (b.shanbi >= m1.Next(12)) 147 { 148 Console.ForegroundColor = ConsoleColor.Yellow; 149 Console.WriteLine(a.name + "对" + b.name + "使用普通攻击,但被" + b.name + "躲过了。"); 150 Console.ForegroundColor = ConsoleColor.Red; 151 //Console.WriteLine(p1.name + "的血量为:" + p1.blood + "," + p2.name + "的血量为:" + p2.blood); Console.WriteLine(p1.name + "的血量为:" + p1.blood + "," + p2.name + "的血量为:" + p2.blood); 152 //Thread.Sleep(1000); 153 } 154 else 155 { 156 b.blood = b.blood - a.attack + b.defence; 157 Console.ForegroundColor = ConsoleColor.Black; 158 Console.WriteLine(a.name + "使用普通攻击,对" + b.name + "造成了" + (a.attack - b.defence) + "点伤害。"); 159 Console.ForegroundColor = ConsoleColor.Red; 160 if (b.blood <= 0)//判断是否为负血量,如果为<0,则让他=0,自己做的时候没想到 161 { 162 b.blood = 0; 163 } 164 //Console.WriteLine(p1.name + "的血量为:" + p1.blood + "," + p2.name + "的血量为:" + p2.blood); 165 //Thread.Sleep(1000); 166 } 167 168 //技能攻击 169 Random m2 = new Random(); 170 int a1 = m2.Next(3); 171 if (m2.Next(2) >= m2.Next(10)) 172 { 173 Console.ForegroundColor = ConsoleColor.Blue; 174 Console.WriteLine(a.name + "释放了" +a.jineng[a1] + ",对" + b.name + "造成了" + a.shanghai[a1] + "伤害。"); 175 b.blood = b.blood - Convert.ToInt32(a.shanghai[a1]); 176 Console.ForegroundColor = ConsoleColor.Red; 177 if (b.blood <= 0)//判断是否为负血量,如果为<0,则让他=0,自己做的时候没想到 178 { 179 b.blood = 0; 180 } 181 //Console.WriteLine(p1.name + "的血量为:" + p1.blood + "," + p2.name + "的血量为:" + p2.blood); 182 //Thread.Sleep(1000); 183 } 184 }//用ref 的目的就是传的a,b的地址这样才能够输出a,b因为战斗而改变的数据 185 186 187 /// <summary> 188 /// 战斗力配置 189 /// </summary> 190 /// <param name="jn">选择3个技能</param> 191 /// <param name="sh">对应出3个技能的伤害</param> 192 /// <param name="p1">对应的玩家</param> 193 /// <returns>返回玩家配置</returns> 194 private static player PlayerPeiZhi(string[] jn, int[] sh, player p) 195 { 196 int seed1 = 0; 197 if (p.name.Length == 2) 198 { 199 seed1 = (int)(Convert.ToChar(p.name.Substring(0, 1))) + (int)(Convert.ToChar(p.name.Substring(1, 1))); 200 } 201 else if (p.name.Length == 3) 202 { 203 seed1 = (int)(Convert.ToChar(p.name.Substring(0, 1))) + (int)(Convert.ToChar(p.name.Substring(1, 1))) + 204 (int)(Convert.ToChar(p.name.Substring(2, 1))); 205 } 206 Random r1 = new Random(seed1); 207 208 p.blood = r1.Next(501) + 3500;//血量 209 p.attack = r1.Next(51) + 250;//攻击力 210 p.defence = r1.Next(21) + 100;//防御力 211 p.shanbi = r1.Next(2) + 2;//闪避 212 p.jineng = new ArrayList();//具体到当前p1.jineng这样集合。把结构体里的jineng类面对p1创建出p1.jineng的对象。 213 p.shanghai = new ArrayList(); 214 215 //技能+伤害 216 for (int i = 0; i < 3; i++) 217 { 218 Random q = new Random(); 219 int a = q.Next(10); 220 if (!p.jineng.Contains(jn[a])) 221 { 222 p.jineng.Add(jn[a]); 223 p.shanghai.Add(sh[a]); 224 } 225 else 226 { 227 i--; 228 } 229 } 230 231 return p; 232 } 233 234 235 /// <summary> 236 /// 技能及伤害 237 /// </summary> 238 /// <param name="jn">技能</param> 239 /// <param name="sh">伤害</param> 240 private static string[] JiNeng(string[] jn,out int[] sh)//或者static void JiNeng(out string[] jn, out int[] sh) 241 { 242 243 jn = new string[10] { "横扫千军", "釜底抽薪", "降龙十巴掌", "雷霆一击", "死亡一指", "紧箍咒", "五雷轰顶", "装嫩", "卖萌", "青年2B打法" }; 244 sh = new int[10] { 300, 350, 351, 311, 280, 350, 300, 280, 300, 300 }; 245 return jn; 246 } 247 248 249 /// <summary> 250 /// 输入姓名 251 /// </summary> 252 /// <param name="a">玩家1</param> 253 /// <param name="b">玩家2</param> 254 private static void ShuRu(ref string a, ref string b)//此处错误,因为a,b传的是值 255 { 256 Console.WriteLine("请输入出战方的姓名:"); 257 a = Console.ReadLine(); 258 Console.WriteLine("请输入防守方的姓名:"); 259 b = Console.ReadLine(); 260 } 261 262 //private static void ShuRu(string a, string b)//此处错误,因为a,b传的是值 263 //{ 264 // Console.WriteLine("请输入出战方的姓名:"); 265 // a = Console.ReadLine(); 266 // Console.WriteLine("请输入防守方的姓名:"); 267 // b = Console.ReadLine(); 268 //} 269 270 }
eg.2 推箱子
1 #region eg 1 推箱子 2 3 4 static void Main1(string[] args) 5 { 6 int a = 1; 7 while (true) 8 { 9 int[,] map = new int[10, 10]; 10 map = Map(a); 11 12 MapDisplay(map); 13 14 int x = ZuoBiao(map, 1, 1); 15 int y = ZuoBiao(map, 1, 2); 16 int r = ZuoBiao(map, 2, 1); 17 int s = ZuoBiao(map, 2, 2); 18 while (map[r, s] != 2) 19 { 20 ConsoleKeyInfo key = Console.ReadKey(); 21 22 #region 向右走 23 if (key.Key.ToString() == "RightArrow") 24 { 25 if (y < 8)//右移最大不会超过y=8坐标 26 { 27 if (map[x, y + 1] == 0)//人的下一步只能是空地,或箱子,或墙,或终点,先判断空地 28 { 29 map[x, y + 1] = 1; 30 map[x, y] = 0; 31 //走过终点后,再让终点恢复出来! 32 //if (a[8, 8] != 2) 33 // a[8, 8] = 3; 34 if (map[r, s] != 2)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 35 map[r, s] = 3; 36 //if (a[8, 6] != 2) 37 // a[8, 6] = 3; 38 y++; 39 40 } 41 else if (map[x, y + 1] == 3)//人的下一步是终点 42 { 43 map[x, y + 1] = 1; 44 map[x, y] = 0; 45 y++; 46 } 47 else if (map[x, y + 1] == 2 && map[x, y + 2] == 0)//人的下一步是箱子 48 { 49 map[x, y + 1] = 1; 50 map[x, y + 2] = 2; 51 map[x, y] = 0; 52 53 //if (a[8, 8] != 2 && a[8, 8] != 1) 54 // a[8, 8] = 3; 55 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 56 map[r, s] = 3; 57 //if (a[8, 6] != 2 && a[8, 6] != 1) 58 // a[8, 6] = 3; 59 60 y++; 61 } 62 else if (map[x, y + 1] == 2 && map[x, y + 2] == 3)//人的下一步是箱子,箱子的下一步是终点 63 { 64 map[x, y + 1] = 1; 65 map[x, y + 2] = 2; 66 map[x, y] = 0; 67 68 //if (a[8, 8] != 2) 69 // a[8, 8] = 3; 70 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 71 map[r, s] = 3; 72 //if (a[8, 6] != 2) 73 // a[8, 6] = 3; 74 75 y++; 76 } 77 else //其中包括,人的下一步是墙,箱子的下一步是墙 78 Console.WriteLine("\a"); 79 } 80 else 81 Console.WriteLine("\a"); 82 } 83 #endregion 84 85 #region 向左走 86 if (key.Key.ToString() == "LeftArrow") 87 { 88 if (y > 1)//左移最小不会小于y=1坐标 89 { 90 if (map[x, y - 1] == 0)//人的下一步只能是空地,或箱子,或墙,先判断空地 91 { 92 map[x, y - 1] = 1; 93 map[x, y] = 0; 94 95 //if (a[8, 8] != 2) 96 // a[8, 8] = 3; 97 if (map[r, s] != 2)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 98 map[r, s] = 3; 99 //if (a[8, 6] != 2) 100 // a[8, 6] = 3; 101 y--; 102 } 103 else if (map[x, y - 1] == 3) 104 { 105 map[x, y - 1] = 1; 106 map[x, y] = 0; 107 y--; 108 } 109 else if (map[x, y - 1] == 2 && map[x, y - 2] == 0)//人的下一步是箱子 110 { 111 map[x, y - 1] = 1; 112 map[x, y - 2] = 2; 113 map[x, y] = 0; 114 115 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 116 map[r, s] = 3; 117 118 y--; 119 } 120 else if (map[x, y - 1] == 2 && map[x, y - 2] == 3)//人的下一步是箱子,箱子的下一步是终点 121 { 122 map[x, y - 1] = 1; 123 map[x, y - 2] = 2; 124 map[x, y] = 0; 125 126 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 127 map[r, s] = 3; 128 129 y--; 130 131 } 132 else //其中包括,人的下一步是墙,箱子的下一步是墙 133 Console.WriteLine("\a"); 134 } 135 else 136 Console.WriteLine("\a"); 137 } 138 #endregion 139 140 #region 向上走 141 if (key.Key.ToString() == "UpArrow") 142 { 143 if (x > 1)//上移不能超过x=8坐标 144 { 145 if (map[x - 1, y] == 0)//人的下一步只能是空地,或箱子,或墙,先判断空地 146 { 147 map[x - 1, y] = 1; 148 map[x, y] = 0; 149 150 //if (a[8, 8] != 2) 151 // a[8, 8] = 3; 152 if (map[r, s] != 2)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 153 map[r, s] = 3; 154 //if (a[8, 6] != 2) 155 // a[8, 6] = 3; 156 157 x--; 158 } 159 else if (map[x - 1, y] == 3)//人下一步是终点,走上去的时候照样替换,走之后,就是人下一步是空地的问题了 160 { 161 map[x - 1, y] = 1; 162 map[x, y] = 0; 163 x--; 164 } 165 else if (map[x - 1, y] == 2 && map[x - 2, y] == 0)//人的下一步是箱子,箱子的下一步是空地 166 { 167 map[x - 1, y] = 1; 168 map[x - 2, y] = 2; 169 map[x, y] = 0; 170 171 //if (a[8, 8] != 2 && a[8, 8] != 1) 172 // a[8, 8] = 3; 173 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 174 map[r, s] = 3; 175 //if (a[8, 6] != 2 && a[8, 6] != 1) 176 // a[8, 6] = 3; 177 178 x--; 179 } 180 else if (map[x - 1, y] == 2 && map[x - 2, y] == 3)//人的下一步是箱子,箱子的下一步是终点 181 { 182 map[x - 1, y] = 1; 183 map[x - 2, y] = 2; 184 map[x, y] = 0; 185 186 //if (a[8, 8] != 2) 187 // a[8, 8] = 3; 188 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 189 map[r, s] = 3; 190 //if (a[8, 6] != 2) 191 // a[8, 6] = 3; 192 193 x--; 194 } 195 else //其中包括,人的下一步是墙,箱子的下一步是墙 196 Console.WriteLine("\a"); 197 } 198 else 199 Console.WriteLine("\a"); 200 } 201 #endregion 202 203 #region 向下走 204 if (key.Key.ToString() == "DownArrow") 205 { 206 if (x < 8)//下移不能超过x=8坐标,只能下走增大,给个上限就可以 207 { 208 if (map[x + 1, y] == 0)//人的下一步只能是空地,或箱子,或墙,先判断空地 209 { 210 map[x + 1, y] = 1; 211 map[x, y] = 0; 212 //if (a[8, 8] != 2) 213 // a[8, 8] = 3; 214 if (map[r, s] != 2)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 215 map[r, s] = 3; 216 //if (a[8, 6] != 2) 217 // a[8, 6] = 3; 218 x++; 219 } 220 else if (map[x + 1, y] == 3)//解决人不能通过终点坐标问题 221 { 222 map[x + 1, y] = 1; 223 map[x, y] = 0; 224 x++; 225 } 226 else if (map[x + 1, y] == 2 && map[x + 2, y] == 0)//人的下一步是箱子,箱子的下一步是空地 227 { 228 map[x + 1, y] = 1; 229 map[x + 2, y] = 2; 230 map[x, y] = 0; 231 232 //if (a[8, 8] != 2 && a[8, 8] != 1) 233 // a[8, 8] = 3; 234 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子,而且人在终点上的,就让显示人,而不是终点 235 map[r, s] = 3; 236 //if (a[8, 6] != 2 && a[8, 6] != 1) 237 // a[8, 6] = 3; 238 239 x++; 240 } 241 else if (map[x + 1, y] == 2 && map[x + 2, y] == 3)//人的下一步是箱子,箱子的下一步是终点 242 { 243 map[x + 1, y] = 1; 244 map[x + 2, y] = 2; 245 map[x, y] = 0; 246 247 //if (a[8, 8] != 2) 248 // a[8, 8] = 3; 249 if (map[r, s] != 2 && map[r, s] != 1)//当箱子推入终点后,如果人的下一步是空地的话,此时就不能让终点的坐标还显示,而是显示箱子 250 map[r, s] = 3; 251 //if (a[8, 6] != 2) 252 // a[8, 6] = 3; 253 254 x++; 255 } 256 else //其中包括,人的下一步是墙,箱子的下一步是墙 257 Console.WriteLine("\a"); 258 } 259 else 260 Console.WriteLine("\a"); 261 } 262 #endregion 263 264 MapDisplay(map); 265 } 266 267 Console.Write("恭喜你过关!按回车键进入下一关:"); 268 ConsoleKeyInfo key1 = Console.ReadKey(); 269 if (key1.Key.ToString().ToLower() == "enter") 270 { 271 a += 1; 272 } 273 else 274 { 275 Console.WriteLine("你输入的有错!"); 276 break; 277 } 278 } 279 } 280 281 /// <summary> 282 /// 构造地图 283 /// </summary> 284 /// <param name="a">关数</param> 285 /// <returns>相应关数的地图</returns> 286 static int[,] Map(int a) 287 { 288 int[,] d = new int[10, 10]; 289 if (a == 1) 290 { 291 int[,] map1 = new int[10, 10]{ 292 {8,8,8,8,8,8,8,8,8,8}, 293 {8,0,0,0,8,0,0,0,0,8}, 294 {8,0,2,0,8,8,8,8,0,8}, 295 {8,0,0,0,0,0,0,8,0,8}, 296 {8,1,0,0,0,0,0,8,0,8}, 297 {8,0,0,0,8,0,0,0,0,8}, 298 {8,0,0,0,8,0,0,0,0,8}, 299 {8,0,3,0,8,0,0,0,0,8}, 300 {8,0,0,0,8,0,0,0,0,8}, 301 {8,8,8,8,8,8,8,8,8,8}}; 302 303 return map1; 304 } 305 else if (a == 2) 306 { 307 int[,] map1 = new int[10, 10]{ 308 {8,8,8,8,8,8,8,8,8,8}, 309 {8,0,0,0,8,0,0,0,0,8}, 310 {8,0,0,0,8,8,8,8,0,8}, 311 {8,0,0,0,0,0,0,8,0,8}, 312 {8,1,0,0,0,0,0,8,0,8}, 313 {8,0,0,0,8,0,0,0,0,8}, 314 {8,0,2,0,8,0,0,0,0,8}, 315 {8,0,0,0,8,0,0,0,0,8}, 316 {8,0,0,0,8,0,0,0,3,8}, 317 {8,8,8,8,8,8,8,8,8,8}}; 318 319 return map1; 320 } 321 else if (a == 3) 322 { 323 int[,] map1 = new int[10, 10]{ 324 {8,8,8,8,8,8,8,8,8,8}, 325 {8,0,0,0,8,0,0,0,0,8}, 326 {8,0,2,0,8,8,8,8,0,8}, 327 {8,0,0,0,0,0,0,8,0,8}, 328 {8,1,0,0,0,0,0,8,0,8}, 329 {8,0,0,0,8,0,0,0,0,8}, 330 {8,0,0,0,8,0,0,0,0,8}, 331 {8,0,0,0,8,3,0,0,0,8}, 332 {8,0,0,0,8,0,0,0,0,8}, 333 {8,8,8,8,8,8,8,8,8,8}}; 334 335 return map1; 336 } 337 else 338 { 339 int[,] map1 = new int[10, 10]{ 340 {8,8,8,8,8,8,8,8,8,8}, 341 {8,0,0,0,8,0,0,0,0,8}, 342 {8,0,2,0,8,8,8,8,0,8}, 343 {8,0,0,0,0,0,0,8,0,8}, 344 {8,0,0,0,0,0,0,8,0,8}, 345 {8,0,0,0,8,0,0,0,0,8}, 346 {8,0,1,0,8,0,0,3,0,8}, 347 {8,0,0,0,8,0,0,0,0,8}, 348 {8,0,0,0,8,0,0,0,0,8}, 349 {8,8,8,8,8,8,8,8,8,8}}; 350 351 return map1; 352 } 353 } 354 355 /// <summary> 356 /// 显示地图 357 /// </summary> 358 /// <param name="a">传入每一关的地图</param> 359 static void MapDisplay(int[,] a) 360 { 361 Console.Clear(); 362 for (int i = 0; i < 10; i++) 363 { 364 for (int j = 0; j < 10; j++) 365 { 366 //Console.ForegroundColor = ConsoleColor.White; 367 368 if (a[i, j] == 1) 369 Console.Write("♀"); 370 else if (a[i, j] == 0) 371 Console.Write(" "); 372 else if (a[i, j] == 3) 373 { 374 //Console.ForegroundColor = ConsoleColor.Red; 375 Console.Write("☆"); 376 // Console.ForegroundColor = ConsoleColor.White; 377 } 378 else if (a[i, j] == 8) 379 Console.Write("■"); 380 else 381 Console.Write("□"); 382 } 383 Console.WriteLine(); 384 } 385 }//显示地图 386 387 /// <summary> 388 /// 计算人和终点的坐标 389 /// </summary> 390 /// <param name="map">每一关的地图</param> 391 /// <param name="a">a=1 人的坐标,a=2是终点的坐标</param> 392 /// <param name="b">b=1 x的坐标,b=2 y的坐标</param> 393 /// <returns>坐标值</returns> 394 static int ZuoBiao(int[,] map, int a, int b) 395 { 396 int m = 0; 397 int[,] aa = map; 398 if (a == 1) 399 { 400 if (b == 1) 401 { 402 for (int i = 0; i < 10; i++) 403 { 404 for (int j = 0; j < 10; j++) 405 { 406 if (aa[i, j] == 1) 407 m = i; 408 } 409 } 410 } 411 else 412 { 413 for (int i = 0; i < 10; i++) 414 { 415 for (int j = 0; j < 10; j++) 416 { 417 if (aa[i, j] == 1) 418 m = j; 419 } 420 } 421 } 422 } 423 else 424 { 425 if (b == 1) 426 { 427 for (int i = 0; i < 10; i++) 428 { 429 for (int j = 0; j < 10; j++) 430 { 431 if (aa[i, j] == 3) 432 m = i; 433 } 434 } 435 } 436 else 437 { 438 for (int i = 0; i < 10; i++) 439 { 440 for (int j = 0; j < 10; j++) 441 { 442 if (aa[i, j] == 3) 443 m = j; 444 } 445 } 446 } 447 } 448 449 return m; 450 }
eg.3
4、函数递归
递归的几个特点
a、递归式,就是如何将原问题划分成子问题。
b、递归出口,递归终止的条件,即最小子问题的求解,可以允许多个出口。
c、界函数,问题规模变化的函数,它保证递归的规模向出口条件靠拢。
引入非递归
从用户使用角度来说,递归真的很简便,对程序宏观上容易理解。递归程序的时间复杂度虽然可以根据T(n)=T(n-1)*f(n)递归求出,其中f(n)是递归式的执行时间复杂度,一般来说,时间复杂度和对应的非 递归差不多,但是递归的效率是相当低的它主要发费在反复的进栈出栈,各种中断等机制上(具体的可 以参考操作系统)更有甚者,在递归求解过程中,某些解会重复的求好几次,这是不能容忍的,这些也 是引入非递归机制的原因之一。
递归转非递归的两种方法
1.一般根据是否需要回朔可以把递归分成简单递归和复杂递归,简单递归一般就是根据递归式来找出递推公式(这也就引申出分治思想和动态规划)。
2.而复杂递归一般就是模拟系统处理递归的机制,使用栈 或队列等数据结构保存回朔点来求解。
例题:
1.求解阶乘
阶乘的定义就是n!=n*(n-1)! 0!=1 1!=1
根据定义我们很容易就想到递归方法,做法如下
int Fact(int n) { if(n==0) return 1; //递归出口 return n*Fact(n-1) //n*Fact(n-1)就是递归式,其中n-1就是界函数 }
2.再看Fibonacci的例子
定义:某项的值等于前两项的和,其中第一和第二项为1。
根据定义我们很容易写出程序,这里就不写出来了,当我们用笔划几下的时候我们是否会发现有很多解是重复求出的。举个例子要求F(5)
F(5)=F(4)+F(3);
F(4)=F(3)+F(2);
F(3)=F(2)+F(1);
其中F(3)求解2次。这显然就是时间的浪费。下面我们用递推技术来转化成非递归从例子可以发现我们可以倒过来求解,即从底到顶把F(n)之前要计算的东西保存下来。
程序就是:
int Fibona(int n) { int p1=1,p2=1; //int a[100]={0}; //a[1]=1,a[2]=1; for(int i=3;i<=n;i++) //从三开始就可以了,后面的return包括1,2 两种情况 { int r=p1; //递推,可以使用数组全部保存 p1=p2; p2+=r; //a=a[i-1]+a[i-2] } return p2; //return a[n]; }