2012-08-15 16 views
6

He escrito un programa donde el usuario puede introducir cualquier número de valores en un vector y se supone que debe devolver los cuartiles, pero me siguen dando un "subíndice del vector fuera de rango" error:hallazgo cuartiles

#include "stdafx.h" 
#include <iostream> 
#include <string> 
#include <algorithm> 
#include <iomanip> 
#include <ios> 
#include <vector> 

int main() { 
    using namespace std; 

    cout << "Enter a list of numbers: "; 

    vector<double> quantile; 
    double x; 
    //invariant: homework contains all the homework grades so far 
    while (cin >> x) 
     quantile.push_back(x); 

    //check that the student entered some homework grades 
    //typedef vector<double>::size_type vec_sz; 
    int size = quantile.size(); 

    if (size == 0) { 
     cout << endl << "You must enter your numbers . " 
         "Please try again." << endl; 
     return 1; 
    } 

    sort(quantile.begin(), quantile.end()); 

    int mid = size/2; 
    double median; 
    median = size % 2 == 0 ? (quantile[mid] + quantile[mid-1])/2 : quantile[mid]; 

    vector<double> first; 
    vector<double> third; 

    for (int i = 0; i!=mid; ++i) 
    { 
     first[i] = quantile[i]; 

    } 

     for (int i = mid; i!= size; ++i) 
    { 
     third[i] = quantile[i]; 
    } 
     double fst; 
     double trd; 

     int side_length = 0; 

     if (size % 2 == 0) 
     { 
      side_length = size/2; 
     } 
     else { 
      side_length = (size-1)/2; 
     } 

     fst = (size/2) % 2 == 0 ? (first[side_length/2]/2 + first[(side_length-1)/2])/2 : first[side_length/2]; 
     trd = (size/2) % 2 == 0 ? (third[side_length/2]/2 + third[(side_length-1)/2])/2 : third[side_length/2]; 

    streamsize prec = cout.precision(); 
    cout << "The quartiles are" << setprecision(3) << "1st" 
     << fst << "2nd" << median << "3rd" << trd << setprecision(prec) << endl; 

    return 0; 

} 
+2

Su comprobación de tamaño completo es mejor que 'if (! Quantile.empty())' – chris

+1

Sus vectores 'primero' y 'tercero' también están vacíos cuando se subencriben. – chris

+1

Debe 'push_back' para agregar a los vectores (primero y tercero), no usar el operador [] – sje397

Respuesta

17

En vez de hacer std::sort(quantile.begin(), quantile.end()) una manera un poco más barato sería

auto const Q1 = quantile.size()/4; 
auto const Q2 = quantile.size()/2; 
auto const Q3 = Q1 + Q2; 

std::nth_element(quantile.begin(),   quantile.begin() + Q1, quantile.end()); 
std::nth_element(quantile.begin() + Q1 + 1, quantile.begin() + Q2, quantile.end()); 
std::nth_element(quantile.begin() + Q2 + 1, quantile.begin() + Q3, quantile.end()); 

esto no ordenar la matriz completa, sino sólo hacer una "entre grupos" del 4 cuartil. Esto ahorra en el tipo "dentro de grupos" que haría un total de std::sort.

Si su matriz quantile no es grande, se trata de una pequeña optimización. Pero el comportamiento de escala de std::nth_element es O(N) sin embargo, en lugar de O(N log N) de std::sort.

0

Si sólo un elemento en el vector, esta instrucción está fuera de rango:

quantile[mid-1] 

"i" a partir de mediados de manera tercera [0] está fuera del rango

for (int i = mid; i!= size; ++i) 
{ 
    third[i] = quantile[i]; 
} 
0

Aquí es un error:

vector<double> first; 
vector<double> third; 

for (int i = 0; i!=mid; ++i) 
{ 
    first[i] = quantile[i]; 
} 

El vector first no tiene ningún contenido, pero se intenta acceder a los contenidos. Mismo problema con third y su ciclo. ¿Quiere usar push_back en su lugar?

1

Debe preasignar los vectores first y third antes de establecer los contenidos.

vector<double> first(mid); 
vector<double> third(size-mid); 

o utilizar push_back en lugar de las asignaciones a first[i] y third[i]

4

Aquí es función de cuantiles que es equivalente de MATLAB con interpolación lineal:

template<typename T> 
static inline double Lerp(T v0, T v1, T t) 
{ 
    return (1 - t)*v0 + t*v1; 
} 

template<typename T> 
static inline std::vector<T> Quantile(const std::vector<T>& inData, const std::vector<T>& probs) 
{ 
    if (inData.empty()) 
    { 
     return std::vector<T>(); 
    } 

    if (1 == inData.size()) 
    { 
     return std::vector<T>(1, inData[0]); 
    } 

    std::vector<T> data = inData; 
    std::sort(data.begin(), data.end()); 
    std::vector<T> quantiles; 

    for (size_t i = 0; i < probs.size(); ++i) 
    { 
     T poi = Lerp<T>(-0.5, data.size() - 0.5, probs[i]); 

     size_t left = std::max(int64_t(std::floor(poi)), int64_t(0)); 
     size_t right = std::min(int64_t(std::ceil(poi)), int64_t(data.size() - 1)); 

     T datLeft = data.at(left); 
     T datRight = data.at(right); 

     T quantile = Lerp<T>(datLeft, datRight, poi - left); 

     quantiles.push_back(quantile); 
    } 

    return quantiles; 
} 

Encuentra cuartiles:

std::vector<double> in = { 1,2,3,4,5,6,7,8,9,10,11 }; 
auto quartiles = Quantile<double>(in, { 0.25, 0.5, 0.75 }); 
0

Esta función de plantilla C++ calcula cuartil para usted:

#include <assert.h> 

template <typename T1, typename T2> typename T1::value_type quant(const T1 &x, T2 q) 
{ 
    assert(q >= 0.0 && q <= 1.0); 

    const auto n = x.size(); 
    const auto id = (n - 1) * q; 
    const auto lo = floor(id); 
    const auto hi = ceil(id); 
    const auto qs = x[lo]; 
    const auto h = (id - lo); 

    return (1.0 - h) * qs + h * x[hi]; 
} 

Para úselo:

std::vector<float> x{1,1,2,2,3,4,5,6}; 
std::cout << quant(x, 0.25) << std::endl; 
std::cout << quant(x, 0.50) << std::endl; 
std::cout << quant(x, 0.75) << std::endl; 
Cuestiones relacionadas