Худший случай быстрой сортировки
От: Буравчик Россия  
Дата: 15.09.15 19:48
Оценка: 5 (1)
Есть быстрая сортировка

void quick_sort(int * a, int left, int right, int & count) {
    int key = a[ (left + right) / 2 ];
    int i = left;
    int j = right;
    
    do {
        while (++count, a[i] < key) ++i;
        while (++count, key < a[j]) --j;
        
        if (i <= j) {
            swap(a[i], a[j]);
            ++i, --j;
        }
    } while (i <= j);
    
    if (left < j) quick_sort(a, left, j, count);
    if (i < right) quick_sort(a, i, right, count);
}


Напишите программу, которая для заданного N формирует перестановку чисел от 1 до N чтобы count (количество перестановок) был максимальным. Является ли найденный вариант перестановки также худшим случаем в отношении глубины рекурсии?

Навеяно/взято с http://dxdy.ru/topic98700.html
Best regards, Буравчик
Re: Худший случай быстрой сортировки
От: Chorkov Россия  
Дата: 16.09.15 14:51
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Есть быстрая сортировка


Б>
Б>void quick_sort(int * a, int left, int right, int & count) {
Б>    int key = a[ (left + right) / 2 ];
Б>    int i = left;
Б>    int j = right;
    
Б>    do {
Б>        while (++count, a[i] < key) ++i;
Б>        while (++count, key < a[j]) --j;
        
Б>        if (i <= j) {
Б>            swap(a[i], a[j]);
Б>            ++i, --j;
Б>        }
Б>    } while (i <= j);
    
Б>    if (left < j) quick_sort(a, left, j, count);
Б>    if (i < right) quick_sort(a, i, right, count);
Б>}
Б>


Б>Напишите программу, которая для заданного N формирует перестановку чисел от 1 до N чтобы count (количество перестановок) был максимальным. Является ли найденный вариант перестановки также худшим случаем в отношении глубины рекурсии?


Б>Навеяно/взято с http://dxdy.ru/topic98700.html


Точно перестановок?
Приведенная реализация считает число сравнений ...
Re[2]: Худший случай быстрой сортировки
От: Буравчик Россия  
Дата: 16.09.15 15:07
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Точно перестановок?

C>Приведенная реализация считает число сравнений ...

И это тоже
В общем интересует худщий случай для:
— количества сравнений
— количества перестановок
— глубины рекурсии
Best regards, Буравчик
Re: Худший случай быстрой сортировки
От: NotImplemented США github.com/NotImplemented
Дата: 16.09.15 17:41
Оценка:
> Здравствуйте, Буравчик, Вы писали:

Перестановки, на которых алгоритм производит максимум сравнений приводят и к максимальной глубине рекурсии.
Единственный момент, на который нужно обратить внимание — перестановка {2,1} дает меньше сравнений, чем {1,2}.
Поэтому обменяем 1 и 2 в результирующей перестановке.
Немного улучшил решение, убрал лишний массив.
E-olymp submission

vector<int> find_adversary(const int n)
{
    vector<int> data(n);

    for(int i = 0; i < n; ++i)
        data[i] = i;

    vector<int> result(n);

    for(int k = n - 1; k >= 0; --k)
    {
        result[data[k/2]] = k+1;
        swap(data[k/2], data[k]);
    }

    swap(*find(result.begin(), result.end(), 1), *find(result.begin(), result.end(), 2));

    return result;
}

void quick_sort(vector<int>& data, int left, int right, int & count) {
 
    int key = data[ (left + right) / 2 ];
    int i = left;
    int j = right;
    
    do {
        while (++count, data[i] < key) ++i;
        while (++count, key < data[j]) --j;
        
        if (i <= j) {
            swap(data[i], data[j]);
            ++i, --j;
        }
    } while (i <= j);
    
    if (left < j) quick_sort(data, left, j, count);
    if (i < right) quick_sort(data, i, right, count);
}

int main()
{
    const int answers[] = {3, 6, 12, 19, 27, 36, 46, 57, 69, 82}; 

    for(int i = 0; i < sizeof(answers)/ sizeof(answers[0]); ++i)
    {
        const int n = i + 2;
        vector<int> adversary = find_adversary(n);
        int count = 0;
        quick_sort(adversary, 0, n-1, count);

        if (count != answers[i])
            cout << "Case #" << i << ": FAILED!" << " Expected: " << answers[i] << " Received: " << count << endl;
        else 
            cout << "Case #" << i << ": PASSED!" << endl;

    }
}
Отредактировано 17.09.2015 8:54 NotImplemented . Предыдущая версия . Еще …
Отредактировано 16.09.2015 18:09 NotImplemented . Предыдущая версия .
Отредактировано 16.09.2015 17:49 NotImplemented . Предыдущая версия .
quick sort adversary
Re[2]: Худший случай быстрой сортировки
От: NotImplemented США github.com/NotImplemented
Дата: 17.09.15 19:10
Оценка: :)
>Здравствуйте, NotImplemented, Вы писали:

>> Здравствуйте, Буравчик, Вы писали:


Если решение неверное, то почему нет вопросов или комментариев? А если верное, то почему нет оценок?
Re: Худший случай быстрой сортировки
От: Кодт Россия  
Дата: 21.09.15 11:15
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>
Б>void quick_sort(int * a, int left, int right, int & count) {
Б>    int key = a[ (left + right) / 2 ];
Б>    int i = left;
Б>    int j = right;
    
Б>    do {
Б>        while (++count, a[i] < key) ++i;
Б>        while (++count, key < a[j]) --j;
        
Б>        if (i <= j) {
Б>            swap(a[i], a[j]);
Б>            ++i, --j;
Б>        }
Б>    } while (i <= j);
    
Б>    if (left < j) quick_sort(a, left, j, count);
Б>    if (i < right) quick_sort(a, i, right, count);
Б>}
Б>


Б>Напишите программу, которая для заданного N формирует перестановку чисел от 1 до N чтобы count (количество перестановок) был максимальным. Является ли найденный вариант перестановки также худшим случаем в отношении глубины рекурсии?


Чтобы максимально углубить рекурсию, нужно, чтобы опорный элемент был минимальным или максимальным в текущем подмассиве.
Тогда результат разбиения [L..R] — будет [L..L], [L+1..R] или [L..R-1], [R..R], и мы получим линейную глубину.
Поскольку опорный элемент берётся из середины, то массив можно нагенерировать, выполнив обход двоичного дерева вглубь.
void make_deepest(DATA* a, int L, int R, DATA& t) {
  int M = (L+R)/2;
  a[M] = t++;
  if (L<M) make_deepest(a, L, M-1, t);
  if (M<R) make_deepest(a, M+1, R, t);
}
void make_deepest(DATA* a, int N) { DATA t = 0; make_deepest(a, 0, N-1, t); }


Чтобы максимизировать count — в твоей трактовке кода, нужно, чтобы количество перестановок было минимальным. Ибо он считает количество пропусков.
Если опорный элемент минимальный, то цикл do-while будет выглядеть так
// итерация 0
count += 0;       i = L;
count += (R-M);   j = M;
swap(a[0], a[M]); i = L+1; j = M-1;
// итерация 1
count += 0;       i = L+1;
count += (M-1-L); j = L;

итого, count += R-L-1.
Таки да: стратегия правильная.

А вот чтобы сделать как можно больше swap-ов... Надо подумать.
Перекуём баги на фичи!
Re: Худший случай быстрой сортировки
От: Кодт Россия  
Дата: 21.09.15 15:20
Оценка:
Здравствуйте, Буравчик, Вы писали:

Инвариант функции — это то, что { a[i] | i <- [L..R] } = {L..R}

Пусть опорное значение для разбиения, взятое из ячейки M=(L+R)/2 или какой угодно другой, равно Q.
Поскольку обмены выполняются только тогда, когда a[i]>=Q и a[j]<=Q, то максимальное количество обменов равно min(Q-L,R-Q)+1

Дальше получается формула для динамического программирования
MaxSwaps(R-L) = S(n) = ...

S(0) = 0 — нет данных, нет обменов
S(1) = 0 — нет альтернатив, нет обменов
S(2) = 1 — возможно, один раз придётся упорядочить
S(n) = max (min(q,n-q)+1 + S(q)+S(n-q-1)) | q <- [0..n]
т.е. выполняем обмены при разбиении и уходим в рекурсию по обеим веткам

в частности,
S(3) = max{ 1+S(0)+S(2), 2+S(1)+S(1) } = max{1+0+1, 2+0+0} = 2
S(4) = max{ 1+S(0)+S(3), 2+S(1)+S(2) } = max{1+0+2, 2+0+1} = 3
S(5) = max{ 1+S(0)+S(4), 2+S(1)+S(3), 3+S(2)+S(2) } = max{1+0+3, 2+0+2, 3+1+1} = 5
S(6) = max{ 1+S(0)+S(5), 2+S(1)+S(4), 3+S(2)+S(3) } = max{1+0+5, 2+0+3, 3+1+2} = 6
S(7) = max{ 1+S(0)+S(6), 2+S(1)+S(5), 3+S(2)+S(4), 4+S(3)+S(3) } = max{1+0+6, 2+0+5, 3+1+3, 4+2+2} = 8
и т.д.

(вроде, ничего не напутал?)
и прослеживается тенденция: желательно, чтобы опорной точкой была именно медиана.
S(n) = m+1 + 2*S(m), где m = floor(n/2)

Таким образом, получается, — либо мы опорным значением выбираем минимум или максимум, — максимизируем глубину и сравнения; либо выбираем медиану, — максимизируем обмены.
В твоём коде count подсчитывает сравнения, — я уже сказал выше.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.