c#二(三)分查找的两种方式
其实;两种方式的实现结果一样,却体现出了不同的思考过程;
地中方式,是在一个while循环中,每次从中间找,不断的去改变low 和 high的 位置,然后求他们的中间位置,知道low=high=0;如果还没有知道值,就直接返回-1;
/// <summary> /// 二分查找方式 /// </summary> /// <param name="arr"></param> /// <param name="target"></param> /// <returns></returns> public static int BinaySearch(int[] arr, int target) { int len = arr.Length; int low = 0; int high = len - 1; //一个while循环就搞定了; while (low <= high) { int middleIndex = (low + high) / 2; int middleValue = arr[middleIndex]; if (middleValue == target) { return middleIndex; } else if (target > middleValue) { //searching in right; low = middleIndex + 1; } else { //searching in left; high = middleIndex - 1; } } //没有找到直接就return return -1; }
然后,是利用我们递归的方式来实现的;如果没有找到,子改变地址,然后recursionly的去searching
/// <summary> /// 这样我们的二分查找的递归方式就出来了; /// 这个方式是我们用递归的方式来实现的; /// 不同的代码实现过程,体现了你不同的思考过程; /// </summary> /// <param name="arr"></param> /// <param name="low"></param> /// <param name="high"></param> /// <param name="target"></param> /// <returns></returns> public static int RecursionlyBinaySearch(int[] arr, int low, int high, int target) { int l = low; int h = high; if (l > h) return -1; int middleIndex = (l + h) / 2; int middleValue = arr[middleIndex]; if (middleValue == target) { //stop finding; return middleIndex; } else if (target > middleValue) { // finding in right; return RecursionlyBinaySearch(arr, middleIndex + 1, high, target); } else { //finding in left; return RecursionlyBinaySearch(arr, l, middleIndex - 1, target); } }
本来,想整一个第三种方式出来的;。。。。。。。。。。。只是本来;
第一种做法,有一个bug,你发现了吗????而且!!!非常不明显;
详细的,请看这里;
https://research.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html
这里还有更详细的介绍:
https://www.quora.com/Why-do-people-use-mid-low+-high-low-2-instead-of-low+high-2
ps:有我们的二分查找,当然就有我们的三分查找,四分,等等;如果再分的更细;就形成了我们一个个的查找,这样的意义并不带,因为,我们内部的查找是串行的,如果能够找到内部的查找是并行的;
那么;这样查找的意义才比较大;
总之,要做好区间的分割;同样的,我给出;两种实现方式;
第一种简单的while实现;
/// <summary> /// 这个怎么去分呢??? /// 分成了三个区间; /// 就是一个不断划分区间,然后进行查找的问题; /// </summary> /// <param name="arr"></param> /// <param name="target"></param> public static int ArrayTernarySearch1(int[] arr, int target) { //开始; int len = arr.Length; int low = 0; int high = len - 1; while (low <= high) { //计算中间位置; int middle1Index = low + (high - low) / 3; int middle2Index = high - (high - low) / 3; //中间值; int middle1Vaule = arr[middle1Index]; int middle2Vaule = arr[middle2Index]; if (target <= middle1Vaule) //做好区间分割; { if (target == middle1Vaule) { return middle1Index; } else { high = middle1Vaule - 1; } } else if (middle1Vaule < target && target <= middle2Vaule) //做好区间分割; { if (target == middle2Vaule) { return middle2Index; } else { low = middle1Index + 1; high = middle2Index - 1; } } else if (target > middle2Vaule) //做好区间分割; { low = middle2Index + 1; } } return -1; }
第二种递归实现;
/// <summary> /// 递归实现; /// 加油,我们把这段时间,给熬过去;窝草你尼玛的比; /// </summary> /// <param name="arr"></param> /// <param name="low"></param> /// <param name="high"></param> /// <returns></returns> public static int RecursionTernarySearch(int [] arr,int low,int high,int target) { if (low > high) return -1; int l = low; int h = high; if(l <= h) { int m1 = l + (h - l) / 3; int m2 = h - (h - l) / 3; int m1Value = arr[m1]; int m2Value = arr[m2]; if (m1Value == target) { return m1; } if (m2Value == target) { return m2; } //区间划分; if (target < m1Value) { RecursionTernarySearch(arr, low, m1 - 1, target); } else if (m1Value < target && target < m2Value) { RecursionTernarySearch(arr, m1 + 1, m2 - 1, target); } else { RecursionTernarySearch(arr, m2 + 1, high, target); } } return -1; } /// <summary> /// 这种方式的思路要清晰一些; /// 非常不错,我们一次性就成功的写正确的代码; /// 效果非常好; /// </summary> /// <param name="arr"></param> /// <param name="target"></param> /// <returns></returns> public static int TernarySearch(int [] arr,int target) { int len = arr.Length; if (len < 0) return -1; int index=RecursionTernarySearch(arr, 0, len - 1,target); return index; }
当然,还有我们的四分;和五分。。。。但这样分下去,就没有多大的意义;