1. 程式人生 > >已排序的陣列中找到k個距離x最近的元素

已排序的陣列中找到k個距離x最近的元素

比如陣列

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;
}