二分查找解决数组元素定位问题
2014-11-01 21:07
253 查看
二分查找(Binary Search)
给定包含 n 个元素的已排序数组 sorted_array[],求给定元素 x 的位置。
递归方式(Recursive)实现
迭代方式(Iterative)实现
[b]给定包含 n 个元素的已排序数组 sorted_array[],求小于等于给定元素 x 的最近位置(Floor Value)。[/b]
给定包含 n 个元素的已排序数组 sorted_array[],求大于等于给定元素 x 的最近位置(Ceiling Value)。
给定包含 n 个元素的已排序数组 sorted_array[],其中可能包含若干重复的元素,求给定元素 x 重复的次数。
给定包含 n 个元素的已排序数组 sorted_array[],但数组被从中间某未知点翻转为 A[],求 A[] 数组中的最小元素。
给定包含 n 个元素的已排序数组 sorted_array[],查找其中元素位置等于元素值的位置(Fixed Point)。
给定包含 n 个元素的数组 array[],查找某高点的值大于左右两侧的值的位置(Peak Position)。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],求给定元素 x 的位置。
最简单直接的办法就是线性查找(Linear Search),从数组的最左端开始,逐个值与 x 进行比较,如果匹配则返回元素位置,如果不匹配则右移一位继续比较,如果比较到末尾仍为找到则返回 -1。由此可知,线性查找的时间复杂度为 O(n)。
二分查找(Binary Search)算法使用了分治法(Divide and Conquer)来不断缩小查找范围,并充分利用已知的信息将查找时间复杂度降低到 O(logn)。
那已知信息就是:数组是已排序的。
这样通过如下步骤可以减少比较次数:
将 x 与数组的中间的值进行比较;
如果 x 与中间的值相等,则直接返回中间值的位置;
如果 x 较小,则若存在必出现在中间值的左侧;
如果 x 较大,则若存在必出现在中间值的右侧;
可以通过递归(Recursive)和迭代(Iterative)两种方式来实现。
递归方式(Recursive)实现:
迭代方式(Iterative)实现:
从上面的代码可知,在最坏情况下需要 logn + 1 次比较操作。每个迭代周期内进行了 2 次比较,除非成功匹配了元素。现在我们来尝试尽量减少比较操作的数量,在 while 循环内仅进行一次比较。
现在我们通过使用二分查找(Binary Search)来解决一些常见问题。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],求小于等于给定元素 x 的最近位置(Floor Value)。
例如:sorted_array[] = [2, 3, 4, 6, 7, 8, 10, 12],x = 9,则 FloorValue = 8。
这里需要考虑几个边界条件:
如果数组内的所有元素都小于 x,则最后一个元素即为 FloorValue。
如果数组内的所有元素都大于 x,则实际上不存在 FloorValue,属于异常情况,返回 -1。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],求大于等于给定元素 x 的最近位置(Ceiling Value)。
例如:sorted_array[] = [2, 3, 4, 6, 7, 8, 10, 12],x = 9,则 CeilingValue = 10。
这里需要考虑几个边界条件:
如果数组内的所有元素都大于 x,则第一个元素即为 CeilingValue。
如果数组内的所有元素都小于 x,则实际上不存在 CeilingValue,属于异常情况,返回 -1。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],其中可能包含若干重复的元素,求给定元素 x 重复的次数。
由于是已排序数组,则相同的元素肯定是连续的。这样可以通过查找 x 的最左侧出现和 x 的最右侧出现,则中间的部分都是 x,出现次数 = right - left + 1。
例如:例如:sorted_array[] = [-1, 2, 3, 8, 8, 8, 8, 10],x = 8,则重复的位置为 [8, 8, 8, 8],则重复次数为 6 - 3 + 1 = 4 次。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],但数组被从中间某未知点翻转为 A[],求 A[] 数组中的最小元素。
实际上数组中的最小元素 x 将数组分成了左右两侧,左侧的大于 x,右侧的也大于 x。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],查找其中元素位置等于元素值的位置(Fixed Point)。
例如:sorted_array[] = { -10, -1, 0, 3, 10, 11, 30, 50 },则 Fixed Point = 3。
问题定义:
给定包含 n 个元素的数组 array[],查找某高点的值大于左右两侧的值的位置(Peak Position)。
例如:array[] = { 1, 3, 20, 4, 1 },则 Peak Value = 20,Peak Position = 2。
本文《二分查找解决数组元素定位问题》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。
给定包含 n 个元素的已排序数组 sorted_array[],求给定元素 x 的位置。
递归方式(Recursive)实现
迭代方式(Iterative)实现
[b]给定包含 n 个元素的已排序数组 sorted_array[],求小于等于给定元素 x 的最近位置(Floor Value)。[/b]
给定包含 n 个元素的已排序数组 sorted_array[],求大于等于给定元素 x 的最近位置(Ceiling Value)。
给定包含 n 个元素的已排序数组 sorted_array[],其中可能包含若干重复的元素,求给定元素 x 重复的次数。
给定包含 n 个元素的已排序数组 sorted_array[],但数组被从中间某未知点翻转为 A[],求 A[] 数组中的最小元素。
给定包含 n 个元素的已排序数组 sorted_array[],查找其中元素位置等于元素值的位置(Fixed Point)。
给定包含 n 个元素的数组 array[],查找某高点的值大于左右两侧的值的位置(Peak Position)。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],求给定元素 x 的位置。
最简单直接的办法就是线性查找(Linear Search),从数组的最左端开始,逐个值与 x 进行比较,如果匹配则返回元素位置,如果不匹配则右移一位继续比较,如果比较到末尾仍为找到则返回 -1。由此可知,线性查找的时间复杂度为 O(n)。
class Program { static void Main(string[] args) { int[] sorted_array = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int index = LinearSearch(sorted_array, 6); Console.WriteLine(index); Console.ReadKey(); } static int LinearSearch(int[] sorted_array, int x) { for (int i = 0; i < sorted_array.Length; i++) { if (sorted_array[i] == x) { return i; } } return -1; } }
二分查找(Binary Search)算法使用了分治法(Divide and Conquer)来不断缩小查找范围,并充分利用已知的信息将查找时间复杂度降低到 O(logn)。
那已知信息就是:数组是已排序的。
这样通过如下步骤可以减少比较次数:
将 x 与数组的中间的值进行比较;
如果 x 与中间的值相等,则直接返回中间值的位置;
如果 x 较小,则若存在必出现在中间值的左侧;
如果 x 较大,则若存在必出现在中间值的右侧;
可以通过递归(Recursive)和迭代(Iterative)两种方式来实现。
递归方式(Recursive)实现:
static void Main(string[] args) { int[] sorted_array = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int index = BinarySearchByRecursive( sorted_array, 0, sorted_array.Length, 6); Console.WriteLine(index); Console.ReadKey(); } static int BinarySearchByRecursive( int[] sorted_array, int left, int right, int x) { if (left <= right) { int middle = left + (right - left) / 2; if (x == sorted_array[middle]) return middle; if (x < sorted_array[middle]) return BinarySearchByRecursive( sorted_array, left, middle - 1, x); return BinarySearchByRecursive( sorted_array, middle + 1, right, x); } return -1; }
迭代方式(Iterative)实现:
static void Main(string[] args) { int[] sorted_array = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int index = BinarySearchByIterative( sorted_array, 0, sorted_array.Length, 6); Console.WriteLine(index); Console.ReadKey(); } static int BinarySearchByIterative( int[] sorted_array, int left, int right, int x) { while (left <= right) { int middle = left + (right - left) / 2; if (x == sorted_array[middle]) return middle; if (x < sorted_array[middle]) right = middle - 1; else left = middle + 1; } return -1; }
从上面的代码可知,在最坏情况下需要 logn + 1 次比较操作。每个迭代周期内进行了 2 次比较,除非成功匹配了元素。现在我们来尝试尽量减少比较操作的数量,在 while 循环内仅进行一次比较。
static void Main(string[] args) { int[] sorted_array = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; for (int i = 0; i < sorted_array.Length; i++) { int index = BinarySearchByIterativeWithLessComparison( sorted_array, 0, sorted_array.Length, i); Console.WriteLine(index); } Console.ReadKey(); } static int BinarySearchByIterativeWithLessComparison( int[] sorted_array, int left, int right, int x) { int middle; while (right - left > 1) { middle = left + (right - left) / 2; if (sorted_array[middle] <= x) left = middle; else right = middle; } if (sorted_array[left] == x) return left; else return -1; }
现在我们通过使用二分查找(Binary Search)来解决一些常见问题。
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],求小于等于给定元素 x 的最近位置(Floor Value)。
例如:sorted_array[] = [2, 3, 4, 6, 7, 8, 10, 12],x = 9,则 FloorValue = 8。
这里需要考虑几个边界条件:
如果数组内的所有元素都小于 x,则最后一个元素即为 FloorValue。
如果数组内的所有元素都大于 x,则实际上不存在 FloorValue,属于异常情况,返回 -1。
static void Main(string[] args) { int[] sorted_array = new int[8] { 2, 2, 4, 6, 7, 8, 10, 12 }; int index = -1; for (int i = 0; i < sorted_array.Length; i++) { index = Floor(sorted_array, sorted_array[i]); Console.WriteLine(index); } index = Floor(sorted_array, 1); Console.WriteLine(index); index = Floor(sorted_array, 5); Console.WriteLine(index); index = Floor(sorted_array, 9); Console.WriteLine(index); index = Floor(sorted_array, 13); Console.WriteLine(index); Console.ReadLine(); } static int Floor( int[] sorted_array, int x) { if (x < sorted_array[0]) return -1; return BinarySearchFloorPosition( sorted_array, 0, sorted_array.Length, x); } static int BinarySearchFloorPosition( int[] sorted_array, int left, int right, int x) { int middle; while (right - left > 1) { middle = left + (right - left) / 2; if (sorted_array[middle] <= x) left = middle; else right = middle; } return left; }
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],求大于等于给定元素 x 的最近位置(Ceiling Value)。
例如:sorted_array[] = [2, 3, 4, 6, 7, 8, 10, 12],x = 9,则 CeilingValue = 10。
这里需要考虑几个边界条件:
如果数组内的所有元素都大于 x,则第一个元素即为 CeilingValue。
如果数组内的所有元素都小于 x,则实际上不存在 CeilingValue,属于异常情况,返回 -1。
static void Main(string[] args) { int[] sorted_array = new int[8] { 2, 2, 4, 6, 7, 7, 10, 12 }; int index = -1; for (int i = 0; i < sorted_array.Length; i++) { index = Ceiling(sorted_array, sorted_array[i]); Console.WriteLine(index); } index = Ceiling(sorted_array, 1); Console.WriteLine(index); index = Ceiling(sorted_array, 5); Console.WriteLine(index); index = Ceiling(sorted_array, 9); Console.WriteLine(index); index = Ceiling(sorted_array, 13); Console.WriteLine(index); Console.ReadLine(); } static int Ceiling( int[] sorted_array, int x) { if (x > sorted_array[sorted_array.Length - 1]) return -1; if (x <= sorted_array[0]) return 0; return BinarySearchCeilingPosition( sorted_array, 0, sorted_array.Length, x); } static int BinarySearchCeilingPosition( int[] sorted_array, int left, int right, int x) { int middle; while (right - left > 1) { middle = left + (right - left) / 2; if (sorted_array[middle] < x) left = middle; else right = middle; } return right; }
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],其中可能包含若干重复的元素,求给定元素 x 重复的次数。
由于是已排序数组,则相同的元素肯定是连续的。这样可以通过查找 x 的最左侧出现和 x 的最右侧出现,则中间的部分都是 x,出现次数 = right - left + 1。
例如:例如:sorted_array[] = [-1, 2, 3, 8, 8, 8, 8, 10],x = 8,则重复的位置为 [8, 8, 8, 8],则重复次数为 6 - 3 + 1 = 4 次。
static void Main(string[] args) { int[] sorted_array = new int[8] { -1, 2, 3, 8, 8, 8, 8, 10 }; int count = CountOccurrences(sorted_array, 8); Console.WriteLine(count); Console.ReadKey(); } static int GetLeftPosition( int[] sorted_array, int left, int right, int x) { int middle; while (right - left > 1) { middle = left + (right - left) / 2; if (sorted_array[middle] >= x) right = middle; else left = middle; } return right; } static int GetRightPosition( int[] sorted_array, int left, int right, int x) { int middle; while (right - left > 1) { middle = left + (right - left) / 2; if (sorted_array[middle] <= x) left = middle; else right = middle; } return left; } static int CountOccurrences( int[] sorted_array, int x) { int left = GetLeftPosition(sorted_array, -1, sorted_array.Length - 1, x); int right = GetRightPosition(sorted_array, 0, sorted_array.Length, x); return (sorted_array[left] == x && x == sorted_array[right]) ? (right - left + 1) : 0; }
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],但数组被从中间某未知点翻转为 A[],求 A[] 数组中的最小元素。
实际上数组中的最小元素 x 将数组分成了左右两侧,左侧的大于 x,右侧的也大于 x。
static void Main(string[] args) { int[] A = new int[8] { 6, 7, 8, 9, 10, 2, 3, 4 }; int minimum = BinarySearchIndexOfMinimumRotatedArray( A, 0, A.Length - 1); Console.WriteLine(minimum); Console.ReadKey(); } static int BinarySearchIndexOfMinimumRotatedArray( int[] A, int left, int right) { int middle; if (A[left] <= A[right]) return left; while (left <= right) { if (left == right) return left; middle = left + (right - left) / 2; if (A[middle] < A[right]) right = middle; else left = middle + 1; } return -1; }
问题定义:
给定包含 n 个元素的已排序数组 sorted_array[],查找其中元素位置等于元素值的位置(Fixed Point)。
例如:sorted_array[] = { -10, -1, 0, 3, 10, 11, 30, 50 },则 Fixed Point = 3。
static void Main(string[] args) { int[] sorted_array = new int[8] { -10, -1, 0, 3, 10, 11, 30, 50 }; int index = -1; index = BinarySearchFixedPosition( sorted_array, 0, sorted_array.Length - 1); Console.WriteLine(index); Console.ReadLine(); } static int BinarySearchFixedPosition( int[] array, int left, int right) { if (right >= left) { int middle = (left + right) / 2; if (middle == array[middle]) return middle; else if (middle > array[middle]) return BinarySearchFixedPosition(array, (middle + 1), right); else return BinarySearchFixedPosition(array, left, (middle - 1)); } return -1; }
问题定义:
给定包含 n 个元素的数组 array[],查找某高点的值大于左右两侧的值的位置(Peak Position)。
例如:array[] = { 1, 3, 20, 4, 1 },则 Peak Value = 20,Peak Position = 2。
static void Main(string[] args) { int[] array = new int[5] { 1, 3, 20, 4, 1 }; int index = -1; index = FindPeakPosition(array); Console.WriteLine(index); Console.ReadLine(); } static int FindPeakPosition(int[] array) { return BinarySearchPeakPosition( array, 0, array.Length - 1); } static int BinarySearchPeakPosition( int[] array, int left, int right) { int middle = left + (right - left) / 2; // compare middle element with its neighbors (if neighbors exist) if ((middle == 0 || array[middle - 1] <= array[middle]) && (middle == array.Length - 1 || array[middle + 1] <= array[middle])) return middle; // if middle element is not peak and its left neighbor is greater than it // then left half must have a peak element else if (middle > 0 && array[middle - 1] > array[middle]) return BinarySearchPeakPosition(array, left, (middle - 1)); // if middle element is not peak and its right neighbor is greater than it // then right half must have a peak element else return BinarySearchPeakPosition(array, (middle + 1), right); }
本文《二分查找解决数组元素定位问题》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。
相关文章推荐
- 递归的定义以及递归的示例(计算阶乘、计算斐波那契数、递归二分查找、回文串递归方法解决、汉诺塔问题、递归选择排序问题)
- 面试OR笔试40——二分查找一个函数解决多个问题
- 使用std::lower_bound和std::upper_bound解决常见的二分查找问题
- SQL SERVER——TempDB问题查找定位与解决
- 如何应对论坛、网上查找资料解决问题低效?
- 如何解决数学软件Maple v9.5在中文Windows下,公式输入中光标定位错误的问题
- 关于STL的vector查找问题 (解决NrNsNtNz_InTitle中 由 文本体中发现的标题未被正确识别出的NrNsNtNz)
- 解决无法打开VS2005查找框问题
- Oracle的SQL语句执行效率问题查找与解决方法
- Oracle中SQL语句执行效率问题的查找与解决
- 利用定位解决一个HTML页面奇怪的布局兼容性问题
- 解决制作根文件系统遇到的共享库查找问题
- 终于解决了在c#里面用鼠标查找窗口的问题,原来如此简单
- 正规表达式 在查找替换中的使用 一个看类似变态问题的解决
- 多域环境下people picker查找不到用户问题的解决
- JBuilder Editor中光标不能正确定位问题的解决
- XML查找Node反斜杠匹配问题及解决[转]
- JBuilder Editor中光标不能正确定位问题的解决
- (provider: SQL 网络接口, error: 26 - 定位指定的服务器/实例时出错) 问题解决啦 O(∩_∩)O哈哈~
- 怎样通过iisapp命令查找pid来解决IIS的cpu占用率过高问题