问题:
有一个循环有序数组A,如{7,8,9,0,1,2,3,4,5,6},不知道其最小值的位置。
那么如何从这样的数组中寻找一个特定的元素呢?
解决:
当然,遍历总是一个办法。当然面试的时候回答遍历估计就直接杯具了。
我的想法是将原数组分段,用首元素s,中间元素m和尾元素e,可以将数组分为两个子数组s1,s2,
那么,必然有至少一个子数组是有序的。那么如何确定那一段是有序的呢?
通过分析可以看到只有3种情况:
●当s就是A中最小的元素时,以下不等式成立:
s <= m <= e
●当最小值位于(s, m]时,则有:
m <= e <= s
●当最小值出现在(m,e]时,则有:
e <= s <= m
所以通过s,m,e的大小关系,可以很轻松的判断出s1和s2哪个是有序的。
通过比较要查找的目标t 与s,m,e的大小关系,可以知道t位于哪个子数组。
若t位于有序的子数组,则用二分查找就可以了。
否则,对无序的子数组重复刚才的过程就可以了。
具体代码如下:
view plaincopy to clipboardprint?
01.#include <stdlib.h>
02.#include <stdio.h>
03.int binarySearch(int target, int array[], int start, int end)
04.{
05. int mid = -1;
06. int l = start - 1;
07. int r = end + 1;
08. while(l+1 != r) {
09. mid = l + (r - l) / 2;
10. if(array[mid] < target) {
11. l = mid;
12. } else {
13. r = mid;
14. }
15. }
16. if(r <= end && array[r] == target) {
17. return r;
18. } else {
19. return -1;
20. }
21.}
22.int search(int target, int array[], int start, int end)
23.{
24. if(start > end){
25. return -1;
26. }
27. int mid = start + (end - start) / 2;
28. int s = array[start];
29. int m = array[mid];
30. int e = array[end];
31. if(s <= m) {
32. if(s <= e) { //mini value is at start
33. return binarySearch(target, array, start, end);
34. } else { //mini value is in range (mid, end]
35. if(target >=s && target <= m) {
36. return binarySearch(target, array, start, mid);
37. } else {
38. return search(target, array, mid+1, end);
39. }
40. }
41. } else { //mini value is in range (start, mid]
42. if(target > m && target <= e) {
43. return binarySearch(target, array, mid + 1, end);
44. } else {
45. return search(target, array, start, mid);
46. }
47. }
48.}
49.int main(int argc, char* argv[])
50.{
51. int t1[] = {7,8,9,0,1,2,3,4,5,6};
52. int i = -1;
53. int index = -1;
54. for(; i< 11; i++) {
55. index = search(i, t1, 0, 9);
56. printf("Find %d at index %d!/n", i, index);
57. }
58. return 0;
59.}