/// <summary> /// * 插值查找算法: /// * 要求:有序,线性结构 /// * 时间复杂度O[log(n)] /// * middle = low + (key - arr[low]) / (arr[high] - arr[low]) * (high - low) /// </summary> /// <param name="arr"></param> /// <param name="des"></param> /// <returns></returns> static int InsertValue_Search(int[] arr, int key, out SearchRecord recorder) { recorder = new SearchRecord(); int search_count = 0; int low = 0; int high = arr.Length - 1; while (low <= high) { ++search_count; int middle = low + (key - arr[low]) / (arr[high] - arr[low]) * (high - low); // recorder.Progress.Add(SearchRecord.FormatProgress(middle, middle)); //先拿中间的值与查找的值比较,大于中间的值,说明查找的值索引在[low,middle) if (key == arr[middle]) { recorder.Index = middle; recorder.Count = search_count; return(middle); } else if (key < arr[middle]) { high = middle - 1; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else { low = middle + 1; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } } recorder.Index = -1; return(-1); }
/// <summary> /// * 二分查找算法: /// * 要求:有序,线性结构 /// * 时间复杂度O[log(n)] /// * 循环实现 /// * middle = (low + high) / 2; /// </summary> /// <param name="arr"></param> /// <param name="des"></param> /// <returns></returns> static int Binary_Search(int[] arr, int key, out SearchRecord recorder) { recorder = new SearchRecord(); int search_count = 0; int low = 0; int high = arr.Length - 1; while (low <= high) { ++search_count; int middle = (low + high) / 2; //先拿中间的值与查找的值比较,大于中间的值,说明查找的值索引在[low,middle) recorder.Progress.Add(SearchRecord.FormatProgress(middle, middle)); if (key == arr[middle]) { recorder.Count = search_count; recorder.Index = middle; return(middle); } else if (key < arr[middle]) { high = middle - 1; recorder.Progress.Add("*" + SearchRecord.FormatProgress(low, high)); } else { low = middle + 1; recorder.Progress.Add("*" + SearchRecord.FormatProgress(low, high)); } } recorder.Index = -1; return(-1); }
/// <summary> /// * 斐波那契 查找: /// * 要求:有序,线性结构 /// * 时间复杂度O[log(n)] /// * middle = low + Fib[k - 1] - 1; /// /// 修改部分: /// 传入数组之后不创建临时数组, 根据数组长度在斐波那契数组中index值, /// 判断 if (mid >= arr.Length) { /// high = mid - 1; fibIndex = fibIndex - 1; /// } else { /// // 原来判断方法 /// } /// </summary> /// <param name="arr">需要查找的原数组</param> /// <param name="key">查找的元素</param> /// <param name="recorder"></param> /// <param name="fibIndex">数组长度在斐波那契数组中index值, 如果不提供, 会自动计算</param> /// <returns></returns> static int Fibonacci_Search_Improved(int[] arr, int key, out SearchRecord recorder, int fibIndex = -1) { recorder = new SearchRecord(); int search_count = 0; int low = 0; int high = arr.Length - 1; int mid = 0; //斐波那契分割数值下标 if (fibIndex < 0) { int k = 0; //获取斐波那契分割数值下标 while (arr.Length > Fib[k] - 1) { k++; } fibIndex = k; } while (low <= high) { ++search_count; // low:起始位置 // 前半部分有f[k-1]个元素,由于下标从0开始 // 则-1 获取 黄金分割位置元素的下标 mid = low + Fib[fibIndex - 1] - 1; recorder.Progress.Add(SearchRecord.FormatProgress(mid, mid)); if (mid >= arr.Length) { // 如果超出数组长度, 选哟查找的元素肯定在分割点左侧 // 这样判断就不需要新建和补齐临时数组了 high = mid - 1; fibIndex = fibIndex - 1; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else { if (arr[mid] > key) { // 查找前半部分,高位指针移动 high = mid - 1; // (全部元素) = (前半部分)+(后半部分) // f[k] = f[k-1] + f[k-1] // 因为前半部分有f[k-1]个元素,所以 k = k-1 fibIndex = fibIndex - 1; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else if (arr[mid] < key) { // 查找后半部分,高位指针移动 low = mid + 1; // (全部元素) = (前半部分)+(后半部分) // f[k] = f[k-1] + f[k-1] // 因为后半部分有f[k-2]个元素,所以 k = k-2 fibIndex = fibIndex - 2; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else { recorder.Count = search_count; recorder.Index = mid; return(mid); } } } recorder.Index = -1; return(-1); }
/// <summary> /// * 斐波那契 查找: /// * 要求:有序,线性结构 /// * 时间复杂度O[log(n)] /// * middle = low + Fib[k - 1] - 1; /// /// 修改部分: /// 传入数组是按照斐波那契长度-1且补齐的数组 /// </summary> /// <param name="arr">原数组按照斐波那契长度-1且补齐</param> /// <param name="key">查找的元素</param> /// <param name="recorder"></param> /// <param name="fibIndex">数组长度在斐波那契数组中index值, 如果不提供, 会自动计算</param> /// <returns></returns> static int Fibonacci_Search(int[] temp, int key, out SearchRecord recorder, int fibIndex = -1) { recorder = new SearchRecord(); int search_count = 0; int low = 0; int high = temp.Length - 1; int mid = 0; //斐波那契分割数值下标 if (fibIndex < 0) { int k = 0; //获取斐波那契分割数值下标 while (temp.Length > Fib[fibIndex] - 1) { fibIndex++; } } while (low <= high) { ++search_count; // low:起始位置 // 前半部分有f[k-1]个元素,由于下标从0开始 // 则-1 获取 黄金分割位置元素的下标 mid = low + Fib[fibIndex - 1] - 1; recorder.Progress.Add(SearchRecord.FormatProgress(mid, mid)); if (temp[mid] > key) { // 查找前半部分,高位指针移动 high = mid - 1; // (全部元素) = (前半部分)+(后半部分) // f[k] = f[k-1] + f[k-1] // 因为前半部分有f[k-1]个元素,所以 k = k-1 fibIndex = fibIndex - 1; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else if (temp[mid] < key) { // 查找后半部分,高位指针移动 low = mid + 1; // (全部元素) = (前半部分)+(后半部分) // f[k] = f[k-1] + f[k-1] // 因为后半部分有f[k-2]个元素,所以 k = k-2 fibIndex = fibIndex - 2; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else { recorder.Count = search_count; //如果为真则找到相应的位置 if (mid <= high) { recorder.Index = mid; return(mid); } else { //出现这种情况是查找到补充的元素 //而补充的元素与high位置的元素一样 recorder.Index = high; return(high); } } } recorder.Index = -1; return(-1); }
/// <summary> /// * 斐波那契 查找: /// * 要求:有序,线性结构 /// * 时间复杂度O[log(n)] /// * middle = low + Fib[k - 1] - 1; /// /// 由于创建数组需要消耗大量时间 (new int[500000] 大约耗时24ms, 但查找过程只需0.03秒左右) /// 所以后面两个版本不再函数中创建新的数组 /// /// 第二种于第三种方法都可以, 耗时差别不大 /// </summary> /// <param name="arr">需要查找的原数组</param> /// <param name="key">查找的元素</param> /// <returns></returns> static int Fibonacci_Search(int[] arr, int key, out SearchRecord recorder) { recorder = new SearchRecord(); int search_count = 0; int low = 0; int high = arr.Length - 1; int mid = 0; //斐波那契分割数值下标 int k = 0; //获取斐波那契分割数值下标 while (arr.Length > Fib[k] - 1) { k++; } //创建临时数组 int[] temp = new int[Fib[k] - 1]; Array.Copy(arr, temp, arr.Length); //序列补充至f[k]个元素 //补充的元素值为最后一个元素的值 for (int i = arr.Length; i < temp.Length; i++) { temp[i] = arr[high]; } #if !DEBUG foreach (var item in temp) { Console.Write(item + " "); } Console.WriteLine(); #endif while (low <= high) { ++search_count; // low:起始位置 // 前半部分有f[k-1]个元素,由于下标从0开始 // 则-1 获取 黄金分割位置元素的下标 mid = low + Fib[k - 1] - 1; recorder.Progress.Add(SearchRecord.FormatProgress(mid, mid)); if (temp[mid] > key) { // 查找前半部分,高位指针移动 high = mid - 1; // (全部元素) = (前半部分)+(后半部分) // f[k] = f[k-1] + f[k-1] // 因为前半部分有f[k-1]个元素,所以 k = k-1 k = k - 1; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else if (temp[mid] < key) { // 查找后半部分,高位指针移动 low = mid + 1; // (全部元素) = (前半部分)+(后半部分) // f[k] = f[k-1] + f[k-1] // 因为后半部分有f[k-2]个元素,所以 k = k-2 k = k - 2; recorder.Progress.Add(SearchRecord.FormatProgress(low, high)); } else { recorder.Count = search_count; //如果为真则找到相应的位置 if (mid <= high) { recorder.Index = mid; return(mid); } else { //出现这种情况是查找到补充的元素 //而补充的元素与high位置的元素一样 recorder.Index = high; return(high); } } } recorder.Index = -1; return(-1); }