关于选择排序,网上,和维基都有完成的解释,他们都是。。。。。。,俺觉得都是,太过于总结话语在概述一些东西;
而我却从最本质的东西,一步一步的深入;在深入的学习过程中,我得到如下非代码层面上的感悟;
1.一个完整的模式(代码或者其他东西)都是通过没有=>part0=>part1=>part2>version0=>viersion1.......versionN=>perfect 最后达到一个完成的形式;
如果你只是去学习和体会最后的那一个完成的版本,而没有经历整个探索的过程,你的体会也不会太多;
2.有时候要学会抽象化和跳跃化的去思考问题,而不是step by step(这有点不具体,下次我结合具体的实例来解释)
3.帮助别人解决问题;并不是直接给出问题的答案或者结果;而是给别人一些引导和资源,让他自己去解决;(这点来自使用stackoverflow提问的感受)
好了,废话不多了;直接从代码开始;开始之前,想尝试做下面的practice;
1.选择数组的第一个data(target)将数组分成两部分;满足: minArr<target<=maxArr;
2.选择数组的第一个data(target)将数组分成两部分;满足: minArr<target<=maxArr; 并将target 放入数组“中间位置“;满足: target greater than left data and less than right data;
3.找出value 在有序数组中的位置;
4.找出value 在无序数组中的位置;这个位置应该满足,它在有序数组中应该具有的位置;greater than left data and less than right data;
5.在不开辟内存的情况下(使用新的数组来存储值)完成问题2;
6.关于递归的学习和使用(具体看这篇文章的后半部分:http://www.cnblogs.com/mc67/p/5114008.html)
7.三种方式来实现我们的额快速排序;(本质的区别只有两种)
关于前面的 5个问题,我就直接上代码;你细细品味(建议在没有看代码前,完成上面的问题)
/// <summary> /// 最基本的;将数组分成两部分;一部分比target小,一部分比target大; /// </summary> /// <param name="arr"></param> static void SplitArray(int[] arr) { int len = arr.Length; int target = arr[0]; List<int> min = new List<int>(len); //为了方便,这里我使用List List<int> max = new List<int>(len); //为了方便,这里我使用List for (int i = 1; i < len; i++) //从第二个元素开始查找; { if (arr[i] < target) { min.Add(arr[i]); } else { max.Add(arr[i]); // as euqual condition,I put it into max; } } } /// <summary> /// split the arr and put the target in the right position(greater than left ,less than right) /// </summary> /// <param name="arr"></param> static void SplitArray1(int[] arr) { int len = arr.Length; int target = arr[0]; List<int> min = new List<int>(len); //为了方便,这里我使用List List<int> max = new List<int>(len); //为了方便,这里我使用List for (int i = 1; i < len; i++) //从第二个元素开始查找; { if (arr[i] < target) { min.Add(arr[i]); } } //put it in the last of min, that can make sure target greater than min(left) min.Add(target); for (int i = 1; i < len; i++) //从第二个元素开始查找; { if (arr[i] > target) { max.Add(arr[i]); } } min.AddRange(max); //that can make sure min<target<max } /// <summary> /// optimze the SplitArray1 /// 上面的代码,还是有问题的,如果有重复的值,那么,将在判断max的时候丢掉; /// 那么问题来了,如果相等的如何判断呢; /// </summary> /// <param name="arr"></param> static void SplitArray2(int[] arr) { int len = arr.Length; int target = arr[0]; List<int> min = new List<int>(len); //为了方便,这里我使用List List<int> max = new List<int>(len); //为了方便,这里我使用List for (int i = 1; i < len; i++) //从第二个元素开始查找; { if (arr[i] < target) { min.Add(arr[i]); } } //put it in the last of min, that can make sure target greater than min(left) min.Add(target); for (int i = 1; i < len; i++) //从第二个元素开始查找; { if (arr[i] >= target) //我们把等于符号加上,就解决问了???? 对于本例子,是从arr[0] 开始的;//那如果是从别的位置开始呢; { max.Add(arr[i]); } } } /// <summary> /// start from random index; /// </summary> /// <param name="arr"></param> static void SplitArray3(int[] arr) { int len = arr.Length; int randomIndex = 2; int target = arr[randomIndex]; //假设,我们从index=2 开始,这里,我们肯定满足arr.length>=2; List<int> min = new List<int>(len); //为了方便,这里我使用List List<int> max = new List<int>(len); //为了方便,这里我使用List for (int i = 0; i < len; i++) //这里,我们就要从0 开始了,遍历整个数组; { if (arr[i] < target) { min.Add(arr[i]); } } min.Add(target); for (int i = 0; i < len; i++) //这里,我们就要从0 开始了,遍历整个数组; { if (arr[i] >= target && i != randomIndex) //加上这个条件,我们就可以过滤到我们的 randomIndex 避免重复添加的问题; { max.Add(arr[i]); } } //最后,我们的数组,就是符合我们要求的数组; } //上面的做法;可以满足 min<target<=max /// <summary> /// 我们来找出元素所在的位置 index 首先是我们的有序数组中 /// 通过值相等来进行判断的话,可以满足; /// 不管值有序 还是 无序的值; /// </summary> static void FindIndex(int[] arr, int value) { int len = arr.Length; int index = -1; for (int i = 0; i < len; i++) { if (arr[i] == value) { index = i; break; } } } /// <summary> /// 两种思维方式, /// 两种思维方式;第二种,更接近普通人的表达方式; /// </summary> /// <param name="arr"></param> /// <param name="value"></param> static void FindIndex1(int[] arr, int value) { int len = arr.Length; int index; bool isExist = false; for (int i = 0; i < len; i++) { if (arr[i] == value) { index = i; isExist = true; break; } } if (isExist == false) { index = 1; } } /// <summary> /// 上面的方法是找到,value,在数组中的第一个index 值; 不管它是否有序; /// 现在我们要找一个元素,在有序列表中的(应该插入的值,但是我们不插入) /// </summary> static void FindIndex2(int[] arr, int value) { int len = arr.Length; int index = -1; for (int i = 0; i < len; i++) { //你可以这么想; //如果找到大于大的数就停止;否则就继续 if (arr[i] >= value) //考虑到取等情况; { index = i; //这个时候,我们的数据,就可以插入在改元素的的后面; index = index - 1; //这样就返回了可以直接插入的位置; //并且停止我们的循环; break; //前提是有序的数组列表中 } } //在插入的时候,就必须把后面的元素往后面挪动; //插入的时候, } /// <summary> /// 上面的方法是找到,value,在数组中的第一个index 值; 不管它是否有序; /// 现在我们要找一个元素,在有序列表中的(应该插入的值,但是我们不插入) /// 2 和 3 两种不同的想法,写出来的code 就不太一样; /// </summary> static void FindIndex3(int[] arr, int value) { int len = arr.Length; int index = -1; for (int i = 0; i < len; i++) { //我们可以可以这么想; if (arr[i] <= value) { index++; //小于它的值,我们的index 就 keep move forward; 还没考虑,我们取等的情况滴呀; } else { //遇到,不满足的情况,我们就退出 //原本的我们的index 是落后于我们的i,出去的时候;再加一次, index++; break; } } //这样就找到了我们的index;在一个可以插入的位置; } /// <summary> /// 先这样来想,找出小于 value的count,那么value在的位置应该就是在我们的count+1; /// </summary> /// <param name="arr"></param> /// <param name="value"></param> static void FindCountLessThan(int[] arr, int value) { int len = arr.Length; int count = 0; for (int i = 0; i < len; i++) { if (arr[i] <= value) { count++; } } //这样,我们就能够找出小于count的数量;那么 我们value所在的位置就是我们count+1 } /// <summary> /// 关键的来了:找到value 应该在的位置;在一个无序的数组中; /// </summary> /// <param name="arr"></param> /// <param name="value"></param> static void FindIndexInUnSortArr(int[] arr, int value) { int len = arr.Length; int rightPosition = 0; //初始化,默认我们的指针在0位置; for (int i = 0; i < len; i++) { //通过遍历来查找; if (arr[i] <= value) { rightPosition++; } } } /// <summary> /// 找到index在的位置,并将小于value的数据放在左边,大于value的数据放在右边 /// </summary> /// <param name="arr"></param> /// <param name="value"></param> static void FindeAndSwap(int[] arr) { int len = arr.Length; int middleIndex = 1; int value = arr[0];//target; // i 能找到一个小于value的值; //middleIndex 始终指向一个大于或等于 value的值; for (int i = 1; i < len; i++) { if (arr[i] <= value) //当找到一个小于value的值之后,进行交换,和那个值进行交换呢;(原则:小的值移动到左边,大的值移动到右边;) { //现在,我们找到了小的值,那么大的值呢;???? if (i == middleIndex) { //不进行交换; keep move } else { Swap(arr, middleIndex, i); } middleIndex++; } } //最后出来后,我们要将第一个元素和中间的元素进行交换,也就是讲value放在middle的位置; Swap(arr, 0, middleIndex - 1); } /// <summary> /// 上面的代码,基本上已经满足了我们额基本要求; /// 完美的代码,解决了这个问题; /// </summary> /// <param name="arr"></param> static int FindeAndSwap1(int[] arr, int start, int end) { int middlePosition = start + 1; int pivot = arr[start]; for (int i = start + 1; i <= end; i++) { if (arr[i] <= pivot) { if (i == middlePosition) { //there is need to swap } else { Swap(arr, middlePosition, i); } middlePosition++; } } //put the arr[start] in "middle position"(greater than left,less than right) int position = middlePosition - 1; Swap(arr, arr[start], position); return position; } /// <summary> /// 同样,我们又第二种方式来实现, /// </summary> /// <param name="arr"></param> /// <param name="low"></param> /// <param name="high"></param> static void FindeAndSwap2(int[] arr, int low,int high) { int l = low-1; //make sure pointer move firstly (before take value from arr to compare with pviot) int h = high+1; //make sure pointer move firstly (before take value from arr to compare with pviot) int pviot = arr[low]; while (l<h) { while (arr[--h]> pviot) //find some value less than pvoit { } while (arr[++l] <= pviot) //find some value greater than pvoit we use <= instead of <;beacause we don‘t let arr[start] swap { } if (l < h) { Swap(arr, h, l); //swap } } Swap(arr, low, h); //put the povit in the "middle" Position } /// <summary> /// 同样,我们也有第三种写法; /// </summary> /// <param name="arr"></param> /// <param name="low"></param> /// <param name="high"></param> static int FindeAndSwap3(int[] arr, int low, int high) { int l = low; int h = high; int pviot = arr[low]; while (l < h) { while (arr[h] >= pviot) //chose >= instead of >; beca if the first value arr[h] equal pviot ,this will enter endless loop;(don‘t enter {} do h--;) { h--; } while (arr[l] <= pviot) //we chose <= instead of < to make sure pviot don‘t take part in swap, we will swap in the last step with "middle" position { l++; } if (l >= h) break; Swap(arr,l,h); } int middlePosition = h; Swap(arr,low, middlePosition); return middlePosition; } /// <summary> /// 当然,就有了,我们的第四种方法; /// 你会发现,前面的方法都是,先找到一个小于的index high 然后找到一个大于的index low /// 然后进行交换; /// 然后有没有其他的方式呢? /// 答案是有的; /// 而且,你会发现,我们的额pvoit 是没有参与swap的,直到我们的最后一步,然后将起放在 middle position(这一步,是不可避免滴呀) /// </summary> /// <param name="arr"></param> /// <param name="low"></param> /// <param name="high"></param> /// <returns></returns> static int FindeAndSwap4(int[] arr, int low, int high) { int pviot = arr[low]; while (low < high) { while(arr[high]>=pviot && low < high) { high--; } //一旦,找到了,我们就替换; arr[low] = arr[high]; //这样,会覆盖我们的第一个值,不过,在最后,我们会将第一个值,放在“中间”位置; while (arr[low] <= pviot && low < high) { low++; } //这样做的话,在没有,进行到最后一步,数组中会有一个重复的值,不过,我们最后将被我们pviot arr[high] = arr[low]; } arr[low] = pviot; return high; } //到了这一步,我们的基本核心的单元,算是基本基本完整了; //然后,我们这里,再实现,三个版本的快速排序;方法; /// <summary> /// 交换 /// </summary> /// <param name="arr"></param> /// <param name="i"></param> /// <param name="j"></param> static void Swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
然后是快速排序的第一种实现方式:
然后是快速排序的第二种实现方式:
原文地址:https://www.cnblogs.com/mc67/p/8259734.html