Медиана двух отсортированных массивов с использованием процедуры сравнения медиан и C++

Я смотрел видео на Youtube, где какой-то стад демонстрирует разные алгоритмы нахождения медианы двух отсортированных массивов: алгоритм подробно описан здесь: https://www.youtube.com/watch?v=_H50Ir-Tves. Я пытаюсь реализовать его алгоритм «Сравнение медиан» и сталкиваюсь с проблемой столба забора или что-то в этом роде. Я решил, что должен просто определить «медиану» как элемент N/2 в массиве из N элементов. Моя реализация в целом грязная и не работает.

Вот функция, которую я использую для сравнения моей другой функции:

template <typename T>
T M2SA_Dumb(std::vector<T> A, std::vector<T> B)
{

    if (A.size() == 0 || B.size() == 0)
        throw std::invalid_argument("Can't find median of 2 sorted arrays if both are empty!");
    std::vector<T> AB;
    AB.reserve(A.size() + B.size());
    AB.insert(AB.end(), A.begin(), A.end());
    AB.insert(AB.end(), B.begin(), B.end());
    sort(AB.begin(), AB.end());
    return (AB[AB.size() / 2]);
}

И вот моя неработающая функция, которую я пытаюсь отладить:

template <typename T>
T M2SA_Smart(const std::vector<T> & A, const std::vector<T> & B)
{
    size_t m(A.size()), n(B.size());
    T retval;
    size_t sizeval = (m > 0 ? 1 : 0) + 2 * (n > 0 ? 1 : 0);
    switch (sizeval)
    {
    case 0: // A, B empty
        throw std::invalid_argument("Can't find median of 2 sorted arrays if both are empty!");
        break;
    case 1: // A non-empty, B empty
        retval = A[m / 2];
        break;
    case 2: // A empty, B non-empty
        retval = B[n / 2];
        break;
    default: // A, B non-empty
        size_t medidx = (m + n) / 2;
        if (A[m - 1] <= B[0])
        {
            if (medidx >= m)
            {
                retval = B[medidx - m];
            }
            else
            {
                retval = A[medidx];
            }
        }
        else if (B[n - 1] <= A[0])
        {
            if (medidx >= n)
            {
                retval = A[medidx - n];
            }
            else
            {
                retval = B[medidx];
            }
        }
        else
        {
            size_t a1(0), a2(m - 1), b1(0), b2(n - 1);
            T M1(A[(a2 - a1) / 2]), M2(B[(b2 - b1) / 2]);
            while (a1 != a2 && b1 != b2)
            {
                if (M1 == M2)
                {
                    retval = M1;
                    break;
                }
                else if (M1 < M2)
                {
                    a1 = (a2 - a1) / 2;
                    b2 = (b2 - b1) / 2;
                }
                else
                {
                    a2 = (a2 - a1) / 2;
                    b1 = (b2 - b1) / 2;
                }
                M1 = A[(a2 - a1) / 2];
                M2 = B[(b2 - b1) / 2];
            }
            retval = std::max(M1, M2);
        }
        break;
    }
    return retval;
}

Я думаю, что проблема в рекурсивной части

    {
        size_t a1(0), a2(m - 1), b1(0), b2(n - 1);
        T M1(A[(a2 - a1) / 2]), M2(B[(b2 - b1) / 2]);
        while (a1 != a2 && b1 != b2)
        {
            if (M1 == M2)
            {
                retval = M1;
                break;
            }
            else if (M1 < M2)
            {
                a1 = (a2 - a1) / 2;
                b2 = (b2 - b1) / 2;
            }
            else
            {
                a2 = (a2 - a1) / 2;
                b1 = (b2 - b1) / 2;
            }
            M1 = A[(a2 - a1) / 2];
            M2 = B[(b2 - b1) / 2];
        }
        retval = std::max(M1, M2);
    }

Происходит что-то неладное. Любая идея, что это???

Для дополнительной информации,

я тестировал

std::vector<int> v1 = { 1, 1, 69, 111, 124 };
std::vector<int> v2 = { 40, 50, 60, 70, 80, 90, 100, 110, 120, 130 };

и получил

M2SA_Dumb(v1, v2) = 80 (правильный ответ)

а также

M2SA_Dumb(v1, v2) = 40 (неправильный ответ)


person Donald Knuth    schedule 28.05.2014    source источник
comment
Вам следует серьезно подумать об изменении имени пользователя.   -  person Ali    schedule 29.05.2014
comment
При обрезке элементов из векторов в рекурсивной части алгоритма количество удаляемых элементов из каждого вектора должно быть одинаковым. Таким образом, если x элементов удаляется из первой части одного вектора, то x элементов удаляется из последней части другого вектора. Логика должна обрабатывать случай, когда векторы имеют разные размеры. Вместо рекурсивного создания новых векторов было бы быстрее использовать индексы для начала и конца каждого вектора.   -  person rcgldr    schedule 29.05.2014


Ответы (1)


Алгоритм, показанный в видео, предназначен для работы с двумя массивами или векторами одинакового размера. Также медиана для массива из четного числа элементов обычно определяется как среднее значение двух средних элементов (поэтому это может быть значение с плавающей запятой, оканчивающееся на .5).

Ссылка на более общий алгоритм для массивов разных размеров:

медиана отсортированных массивов разного размера

Я не уверен, что это практично. Массив или вектор из 4 миллионов 64-битных целых чисел можно отсортировать менее чем за 1 секунду на большинстве современных ПК с помощью сортировки слиянием или быстрой сортировки. std::merge двух отсортированных массивов или векторов или std::list::merge двух отсортированных списков займет небольшую долю секунды.

person rcgldr    schedule 29.05.2014