比如数组
arr[] = {12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56}
假设我们要找距离35这个元素最近的4个元素。
我们计算每个元素距离35的大小:
23 19 13 5 0 4 7 10 13 15 18 20 21
所以最近的4个元素是
30 39 42 45
思路:
1、用折半查找找到和35最接近的元素的位置。这里是35。位置为4。
2、然后设置两个指针(数组索引)指向它的一前(first)一后(next)的元素。
因为数组是排好序的,所以最近的那个元素肯定是first指向的元素和next指向的元素中的某一个。
比较它们距离35的大小(比如以上例子中first指向的元素距离35的大小是45,next指向的元素距离35的位置是4)
所以打印30。如果选择first,则first--,否则next--。直到打印出k个元素。
实际编码中要考虑分界情况:
①35在头部
②35在尾部
③first和next中的某一个在移动的过程中到达数组边界了。
代码来源:http://www.geeksforgeeks.org/find-k-closest-elements-given-value/
#include<stdio.h>
/* Function to find the cross over point (the point before
which elements are smaller than or equal to x and after
which greater than x)*/
int findCrossOver(int arr[], int low, int high, int x)
{
// Base cases
if (arr[high] <= x) // x is greater than all
return high;
if (arr[low] > x) // x is smaller than all
return low;
// Find the middle point
int mid = (low + high)/2; /* low + (high - low)/2 */
/* If x is same as middle element, then return mid */
if (arr[mid] <= x && arr[mid+1] > x)
return mid;
/* If x is greater than arr[mid], then either arr[mid + 1]
is ceiling of x or ceiling lies in arr[mid+1...high] */
if(arr[mid] < x)
return findCrossOver(arr, mid+1, high, x);
return findCrossOver(arr, low, mid - 1, x);
}
// This function prints k closest elements to x in arr[].
// n is the number of elements in arr[]
void printKclosest(int arr[], int x, int k, int n)
{
// Find the crossover point
int l = findCrossOver(arr, 0, n-1, x); // le
int r = l+1; // Right index to search
int count = 0; // To keep track of count of elements already printed
// If x is present in arr[], then reduce left index
// Assumption: all elements in arr[] are distinct
if (arr[l] == x) l--;
// Compare elements on left and right of crossover
// point to find the k closest elements
while (l >= 0 && r < n && count < k)
{
if (x - arr[l] < arr[r] - x)
printf("%d ", arr[l--]);
else
printf("%d ", arr[r++]);
count++;
}
// If there are no more elements on right side, then
// print left elements
while (count < k && l >= 0)
printf("%d ", arr[l--]), count++;
// If there are no more elements on left side, then
// print right elements
while (count < k && r < n)
printf("%d ", arr[r++]), count++;
}
/* Driver program to check above functions */
int main()
{
int arr[] ={12, 16, 22, 30, 35, 39, 42,
45, 48, 50, 53, 55, 56};
int n = sizeof(arr)/sizeof(arr[0]);
int x = 35, k = 4;
printKclosest(arr, x, 4, n);
return 0;
}