c# for 和 while的区别
for 用来遍历,while 也用来遍历;看是功能相同的,但如果功能相同,为啥不剔除一个呢;(而且几乎所有编程语言都有这两个循环语句)
因为他们有不一样的地方呀,(感觉好像废话,我们还是具体看代码吧)
相同的地方;
public static void TestLoop1() { int loopTimes = 4; int i; for(i = 0; i < loopTimes; i++) { //0 //1 //2 //3 //最后一次进来是 index=3; //出去的时候,index 还是3 } //(累加=>停止循环的时候变成了4 int index = 0; while (index < loopTimes) { //0 //1 //2 //3 //最后一次进来 index=3; index++; //累加 然后出去,index=4; 然后不满足条件;退出循环; } //眨眼一看,上面的写法没什么区别; BUT i 的叠加是在 {} 外部进行的, index 的叠加是在 {} 内部进行的; }
上面的写法,在开发中会遇到不同的问题,比如:
//眨眼一看,上面的写法没什么区别; BUT i 的叠加是在 {} 外部进行的, index 的叠加是在 {} 内部进行的; //这样会出现什么问题呢; Console.WriteLine("我们来遍历一次数组,就知道了"); Console.WriteLine("for......."); var arr = new int[] {1,2,3,4}; int len = arr.Length; for(int j = 0; j < len; j++) { Console.WriteLine(arr[j]); //这个数绝对安全的; } Console.WriteLine("while....."); int k = 0; while (k < len) { //k++; 如果k++放在前面,无法比那里k=0 这个数组不说,还会发生数组越界的异常; Console.WriteLine(arr[k]); k++; } Console.WriteLine("finall k index;"+k); //最后这个index 会变成4 所以这样比那里数组是不安全的; //你以为区别就这一点吗? 太年轻了,接着看;
不同的地方;
static void ForVSWhile() { var arr=new []{ 1,2,4,5,6}; int len = arr.Length; int target = 4; for (int i = 0; i < len; i++) { if (arr[i] == target) { break; } } //这个就相当于我们的while; int index = 0; while (arr[index] == target) //找到我们想要的元素后,就立马停止; { index++; } }
不过,你也可以把他们写来一样,不过,感觉好别扭;
var arr=new []{ 1,2,4,5,6}; int len = arr.Length; int target = 4; for (int i = 0; i < len && arr[i] == target; i++) { }
我们再来看一个容易出错的地方;
/// <summary> /// 找出数组中小于target的值; /// 这个问题,我在快速排序的时候遇到的一个死循环; /// </summary> public static void TestLoop2() { var arr = new int[] { 1,2,1}; int len = arr.Length; int target = 2; List<int> list = new List<int>(3); List<int> list1 = new List<int>(3); // 常规写法; for(int j = len-1; j>=0; j--) { if (arr[j] < target) { list.Add(arr[j]); } } Console.WriteLine("while写法的结果--------------:"); //index=2; int k = len-1; //因为 arr[1]=2 不满足条件,然后就退出了循环;并没有遍历我们的整个数组; //并没有把我们的数组遍历完; while (arr[k] < target) { list1.Add(arr[k]); k--; } }
其实,对这个问题的总结,来自我们的快速排序时,遇到的一个问题;
static void TestLoop() { //在快速排序的过程中遇到一个问题; var arr = new[] { 5, 4,1 }; int len = arr.Length; int high = len - 1; int low = 0; int middle = arr[1]; while (low < high) { while (arr[high] > middle && low<high) { high--; } while (arr[low] < middle && low < high) { low++; } } //高地址 middle=4 high=2; arr[2]=1 找到了小于 middle 的值; 这时候,我们的high=2; //底地址 middle=4 low=0; arr[0]=5;找到了大于 middle 的值; 这时候 我们的low=0; // 这个时候,进行交换 arr[2] 和 arr [0] 数组变了 1 4 5 // 但是 关键来了!!!!!!!!!!!!!!! // 进行寻址之后 我们的 high 和 low 没有 进行 递减 和 递增的操作, high还是2 low 还是 0 //这样就形成了我们的死循环;窝草; //这样就被迫,我去思考一些基础性的问题;之前也遇到过 如 ++i 和 i++; 如 for 循环 和while 循环的区别; }
然后,这里我们再来复习一个非常简单的额问题;i++; 和 ++i;
i++; 先进行赋值,然后再进行累加;
我们来看一个以此产生的死循环;
/// <summary> /// 如果这样写,tad的就变成了死循环哈 /// </summary> /// <param name="n"></param> static void TestRecursion(int n) { if (n > 0) { Console.WriteLine(n); TestRecursion(n--); //先将n进行函数赋值进行运算,然后再n--;如果这样搞就是死循环啊; } }
fix(这样就好了)
/// <summary> /// 如果这样写,tad的就变成了死循环哈 /// </summary> /// <param name="n"></param> static void TestRecursion2(int n) { if (n > 0) { Console.WriteLine(n); TestRecursion2(--n); //先将n进行函数赋值进行运算,然后再n--;如果这样搞就是死循环啊; } }
然后,我们再来看一个取值的问题;
static void TestWhile() { var arr = new[] {1,2,3,4}; int len = arr.Length; var newArr = new int[len]; int index = 0; var newArr1 = new int[len]; int index1 = 0; for (int i = 0; i < len; i++) { if (arr[i] % 2 == 0) { newArr[++index] = arr[i]; //从结果中可以看出,++i 是先累加,在赋值 newArr1[index1++] = arr[i]; //从结果中可以看出,i++ 是先赋值,在累加 } } //然后我们来看这两个的区别; Console.WriteLine("++index"); foreach (int i in newArr) { Console.WriteLine(i); } Console.WriteLine("index++"); foreach (int i in newArr1) { Console.WriteLine(i); } }
结果:
然后,我们看看,在while 中应用,主要是是在我们的快速排序中;也就是修复我们前面那个快速排序中的死循环;
static void TestLoop() { //在快速排序的过程中遇到一个问题; var arr = new[] { 5, 4,1 }; int len = arr.Length; int high = len - 1; int low = 0; //这里写个重负代码,主要为了,看得清楚一点; high = high + 1; low = low - 1; int middle = arr[1]; while (low < high) { while (arr[--high] > middle && low<high) //先尽心一次自减。再取值; { int xx = 0; } while (arr[++low] < middle && low < high) ////先尽心一次自加。再取值; //这样,保证,我们每一次遍历,都在前进;就想我们的for循环;知道low 遇到我们的i { int xx = 0; } }
然后,我们再来看一个具体的实例优化;找到元素应该插入的位置;如:target =2; 在 0 1 中,应该插入的位置就是2;如果用for来实现;则会出现如下的代码;
/// <summary> /// 找到元素应该在的正确元素; /// 考虑下面三种情况; /// 1.数组长度就是1; /// 2.找完了,都没找到; /// 找到,应该插入的位置;。。。shit优化; /// </summary> public static int FindRightPostion(int [] arr,int target) { int len = arr.Length; int position =0; //如果没有找到,就应该在第一个位置;最后一个步,却加了1,这样。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。、 bool isFind = false; //正向寻找; for(int i = 0; i < len; i++) { //最后一次没有进来;对,i就是我们的待插入的位置;不过,最后一次的条件没有进来; if (arr[i]<target) //最后一个找到,肯定是不满足条件的的; { position = i; //不满足条件的值,没有进入这个赋值;所以,最后合适的位置就是;position+1 isFind = true; } else { break; } } if (isFind == false) return position; else return position+1; } /// <summary> /// 这种方式也不错滴啊; /// </summary> /// <param name="arr"></param> /// <param name="target"></param> /// <returns></returns> public static int FindRightPostion2(int[] arr, int target) { int len = arr.Length; int position = 0; for (int i = 1; i < len; i++) { if (arr[i] < target) { position = i; } else { break; } } return position == 0 ? 0 : position + 1; }
然后,如果用我们的while 来实现,这样的方式,代码,好了很多;(这样,就完美多了)
/// <summary> /// 这样写,比较合适,出来的时候,pointer 恰好;执向的是下一个位置; /// </summary> /// <param name="arr"></param> /// <param name="target"></param> /// <returns></returns> public static int FindeRightPostion(int [] arr,int target) { int len = arr.Length; int pointer = 0; while (pointer < len && arr[pointer] < target) { pointer++; } return pointer; }
总结:for 循环,更多用于一个完整的遍历; while 更多是带有终止条件的遍历;