Blame statistics/select_source.c

Packit 67cb25
/* statistics/select_source.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 2018 Patrick Alken
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#define SWAP(a,b) do { tmp = b ; b = a ; a = tmp ; } while(0)
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
gsl_stats_select()
Packit 67cb25
  Select k-th largest element from an unsorted array using
Packit 67cb25
quickselect algorithm
Packit 67cb25
Packit 67cb25
Inputs: data   - unsorted array containing the observations
Packit 67cb25
        stride - stride
Packit 67cb25
        n      - length of 'data'
Packit 67cb25
        k      - desired element in [0,n-1]
Packit 67cb25
Packit 67cb25
Return: k-th largest element of data[]
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
BASE
Packit 67cb25
FUNCTION(gsl_stats,select) (BASE data[],
Packit 67cb25
                            const size_t stride,
Packit 67cb25
                            const size_t n,
Packit 67cb25
                            const size_t k)
Packit 67cb25
{
Packit 67cb25
  if (n == 0)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR_VAL("array size must be positive", GSL_EBADLEN, 0.0);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      size_t left = 0;
Packit 67cb25
      size_t right = n - 1;
Packit 67cb25
      size_t mid, i, j;
Packit 67cb25
      BASE pivot, tmp;
Packit 67cb25
Packit 67cb25
      while (1)
Packit 67cb25
        {
Packit 67cb25
          if (right <= left + 1)
Packit 67cb25
            {
Packit 67cb25
              if (right == left + 1 && data[right * stride] < data[left * stride])
Packit 67cb25
                {
Packit 67cb25
                  SWAP(data[left * stride], data[right * stride]);
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              return data[k * stride];
Packit 67cb25
            }
Packit 67cb25
          else
Packit 67cb25
            {
Packit 67cb25
              mid = (left + right) >> 1;
Packit 67cb25
              SWAP(data[mid * stride], data[(left + 1) * stride]);
Packit 67cb25
Packit 67cb25
              if (data[left * stride] > data[right * stride])
Packit 67cb25
                {
Packit 67cb25
                  SWAP(data[left * stride], data[right * stride]);
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              if (data[(left + 1) * stride] > data[right * stride])
Packit 67cb25
                {
Packit 67cb25
                  SWAP(data[(left + 1) * stride], data[right * stride]);
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              if (data[left * stride] > data[(left + 1) * stride])
Packit 67cb25
                {
Packit 67cb25
                  SWAP(data[left * stride], data[(left + 1) * stride]);
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              i = left + 1;
Packit 67cb25
              j = right;
Packit 67cb25
              pivot = data[(left + 1) * stride];
Packit 67cb25
Packit 67cb25
              while (1)
Packit 67cb25
                {
Packit 67cb25
                  do i++; while (data[i * stride] < pivot);
Packit 67cb25
                  do j--; while (data[j * stride] > pivot);
Packit 67cb25
Packit 67cb25
                  if (j < i)
Packit 67cb25
                    break;
Packit 67cb25
Packit 67cb25
                  SWAP(data[i * stride], data[j * stride]);
Packit 67cb25
                }
Packit 67cb25
Packit 67cb25
              data[(left + 1) * stride] = data[j * stride];
Packit 67cb25
              data[j * stride] = pivot;
Packit 67cb25
Packit 67cb25
              if (j >= k)
Packit 67cb25
                right = j - 1;
Packit 67cb25
Packit 67cb25
              if (j <= k)
Packit 67cb25
                left = i;
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* will never get here */
Packit 67cb25
      GSL_ERROR_VAL("select error", GSL_FAILURE, 0.0);
Packit 67cb25
    }
Packit 67cb25
}