Оценка эффективности и быстродействия различных алгоритмов.

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by c0n Difesa, 11 Oct 2009.

  1. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Существует множество способов решения определенной задачи (класса задач). Это множество порождает обилие алгоритмов, которые ее решают. Однако из этого набора алгоритмов можно выбрать те, которые справляются с поставленной задачей (классом задач) быстрее остальных, используя меньше ресурсов процессора и /или оперативной памяти.

    Цель данного топика: рассмотреть как можно больше алгоритмов, оценить их временную сложность и определить границы эффективного применения. Границы эффективного применения – класс задач, для которого рассматриваемый алгоритм будет наиболее быстродейственным.

    В качестве примера рассмотрим алгоритм сортировки массива методом вставки. Помимо этого я покажу как лучше оформлять сообщение, содержащее обзор алгоритма.


    Сортировка массива методом вставки.

    1. Псевдокод (справка: _http://ru.wikipedia.org/wiki/Псевдокод_(язык_описания_алгоритмов)), описывающий рассматриваемый алгоритм.

    Code:
    InsertionSort(list, N)
    list //исходный массив
    N //количество элементов в массиве
    for j = 2 to N do
         newelement = list[j];
         location = j - 1;
         while (location >= 1) and (list[location]>newelement) 
               list[location + 1] = list[location];
               location = location - 1;
         end while;
         list[location + 1] = newelement;
    end for;
    2. Оценка временной сложности.

    Временная сложность - скорость увеличения числа операций при возрастании размерности задачи.

    Например, пусть алгоритм содержит внешний цикл C1 с числом операций N1 и внутренний цикл C2 с числом операций N2, тогда временная сложность определяется следующим образом:
    Code:
    T(N) = C1 * N1 * C2 * N2   ~= С1 * С2 * (N^2) = O (N^2).
    Скорость определяется элементом, стоящим в скобках.

    Применим формулу к рассматриваемому алгоритму.

    В лучшем случае (когда элементы массива уже упорядочены: [1, 2, 3, 4]):

    Code:
    T(N) = O (N).
    В худшем случае (все элементы массива расположены в обратном порядке: [4, 3, 2, 1]):

    Code:
    T(N) = O ((N^2)/4).
    3. Вывод.

    Алгоритм сортировки методом вставки является наиболее быстродейственным для небольших массивов, с высокой степенью начальной упорядоченности.
     
    #1 c0n Difesa, 11 Oct 2009
    Last edited: 11 Oct 2009
    3 people like this.
  2. Irdis

    Irdis Elder - Старейшина

    Joined:
    6 Feb 2006
    Messages:
    248
    Likes Received:
    52
    Reputations:
    3
    Сортировка массива методом перестановки.
    Дан массив из n чисел, отсортировать его по возврастанию.
    Решение:
    Будем генерировать все возможные перестановки из n элементов.
    Среди всех возможных перестановок из n эл., существует такая в которой элементы расставлены в неубывающем порядке.
    Завершаем алгоритм.

    Временная сложность. В худшем случае требуется перебрать n! перестановок.

    Вывод.
    Более неэффективного алгоритма сортировки не существует.
    -----------------------
    2ErrorNeo Предложенный тобой алгоритм не решает задачу сортировки массива, т.к. он не всюду применим(он может не отсортировать данный массив за конечное время, т.е. мы не узнаем работает алгоритм или нет =) )
     
    #2 Irdis, 12 Oct 2009
    Last edited: 12 Oct 2009
  3. ErrorNeo

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    существует.
    можно генерировать рандомные варианты перестановок из n эл. до тех пор, пока массив не окажется упорядоченным.
    Если повезет - такой метод перестановки отработает всю сортировку за 1 перестановку. Если нет- решение может занять намного дольше твоего метода, т.к. каждая новая попытка в данном случае не увеличивает вероятности "успешного попадания".

    А вообще самый быстрый из существующих методов сортировки массивов называется "quicksort"
    http://ru.wikipedia.org/wiki/Быстрая_сортировка

    метод описанный в первом посте - http://ru.wikipedia.org/wiki/Сортировка_вставками
     
  4. Nikituki

    Nikituki New Member

    Joined:
    14 Mar 2009
    Messages:
    19
    Likes Received:
    3
    Reputations:
    0
    Не соглашусь... У быстрой сортировки в худшем случае O(N^2), а в среднем O(N*log N).
    У пирамидальной сортировки в любом случае (тоесть и в лучшем, и в худшем, и в среднем) O(N*log N).
    Так же существует еще и поразрядная сортировка, которая вообще линейна...
     
    1 person likes this.
  5. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Сортировка методом "пузырька".

    1. Псевдокод.

    Code:
    NOF = N;
    SE = true;
    while SE do
         NOF = NOF -1;
         SE= false;
         for i = 1 to NOF do
              if list[i] > list[i + 1] then
                   swap(list[i], list[i+1]);//поменять местами
                   SF = true;
              end if
         end for
    end while.
    
    2. Оценка временной сложности.

    В лучшем случае (все элементы уже упорядоченны):
    Code:
    T(n) = O(N)
    В худшем случае (элементы расположены в обратном порядке):
    Code:
    T(n) = (N - 1) + (N - 2) + ... + 1= O(N^2)
    3. Вывод.

    Простой алгоритм сортировки, эффективный для небольших массивов, однако, прост для понимания и легок для реализации.
     
  6. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Сортировка простым выбором.

    1. Псевдокод

    Code:
    var
         lowkey: keytype;
         lowindex: integer;
    Begin
    for i = 1 to (n -1) do
         lowindex = j;
         lowkey = A[j].key;
         for k = j + 1 to N do
              if A[k].key < lowkey then
                   lowkey = A[k].key;
                   lowindex = k;
              end if;
              swap (A[j], A[lowindex]);//поменять местами
         end for;
    end.
    
    2. Оценка эффективности.

    На массиве из n элементов имеет время выполнения в худшем, среднем и лучшем случае:

    Code:
    T(n) = O(N^2)
    (c) Wikipedia

    3. Вывод.

    Неустойчивый алгоритм сортировки, обладающий одинаковым временем сортировки для небольших массивов разной степени упорядоченности, что делает его наиболее универсальным в своем классе.
     
  7. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Сортировка Шелла.

    1. Псевдокод.

    Code:
    ShellSort(list, N)
    list//массив элементов
    N//количество элементов в массиве
    passes = log2(N);
    while (passes >= 1)  do
         increment = 2^(passes-1) – 1;
         for start = 1 to increment do
              InsertSort(list, N, start, increment)//сортировка полученного набора методом вставки
         end for;
    end while.
    
    2. Оценка эффективности.

    В худшем случае:
    Code:
    T(n) = O(N^(3/2))
    3. Вывод.

    Невзирая на то, что сортировка Шелла во многих случаях медленнее, чем быстрая сортировка, она имеет ряд преимуществ:
    -отсутствие потребности в памяти под стек
    -отсутствие деградации при неудачных наборах данных — qsort легко деградирует до O(N^2), что хуже, чем худшее гарантированное время для сортировки Шелла

    Часто оказывается, что сортировка Шелла есть самый лучший способ сортировки до, примерно, 1000 элементов. (с) Wikipedia
     
  8. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    как же вы надоели со своими квадратичными (да и вообще) сортировками!
    Кому очень интересно узнать всё в детелях и подробностях, вникнуть во все реккуренты - добро пожаловать, у Кнута целый том.

    Плюс жалкие намёки на оценку сложности. Ну в худшем случае O(g(n)). И что? Где средние оценки времени?? Где оценки, например, среднего количества обменов элементов?
     
    1 person likes this.
  9. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Данный топик создан с целью анализа алгоритмов вообще, а не только алгоритмов сортировок. Более сложные алгоритмы опираются на базовые (к коим относятся сортировки), поэтому считаю нужным рассмотреть базовую часть, чтобы перейти к более сложным обзорам.

    Не каждый осилит «Кнута», потому что книга насыщена математическими выкладками. Чтобы сравнить два алгоритма и определить, какой лучше использовать в нужном случае не обязательно «копаться» в лишнем материале. Достаточно разложить свой алгоритм на базовые алгоритмы и, проанализировав каждую часть, сделать вывод в общих чертах.

    Средние оценки у Кнута ;) А если серьезно: большинство из рассмотренных на данный момент алгоритмов сортировок имеют оценку в среднем случае эквивалентную худшему случаю. Иначе – я уточняю.

    P.S. Спасибо за замечания.
     
  10. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    >>книга насыщена математическими выкладками
    А что же такое "анализ алгоритмов" без математики?

    и не надо аппелировать к термину "класс задач" - у него немного другой смысл.
     
  11. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Согласен, выполнять анализ без математических методов трудно. Но здесь это не требуется - достаточно написать конечные результаты и сделать по ним выводы.

    Прошу Вас дать свой вариант определения "класса задач", чтобы заполнить пробел.
     
    #11 c0n Difesa, 18 Oct 2009
    Last edited: 18 Oct 2009
  12. BrainDeaD

    BrainDeaD Elder - Старейшина

    Joined:
    9 Jun 2005
    Messages:
    774
    Likes Received:
    292
    Reputations:
    214
    Аппелировать = обращаться))
     
    1 person likes this.
  13. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    под классом задач обычно понимают http://ru.wikipedia.org/wiki/Класс_сложности


    >>достаточно написать конечные результаты и сделать по ним выводы.
    так напиши полезные результаты (а не пузырёк), и полные выводы. Например, сколько в среднем (по всем входным массивам) работает тот же пузырёк, и сколько обменов он совершает в среднем?
     
  14. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Из Википедии:
    Чтобы не быть голословным, объясните, где в своих постах я использовал данный термин не "по назначению".

    Я понимаю что метрика "среднего случая" для Вас крайне важна, но не настолько, чтобы она стояла по приоритетам выше "худший случай" и "лучший случай", которых вполне достаточно для сравнения алгоритмов по эффективности.
     
  15. desTiny

    desTiny Elder - Старейшина

    Joined:
    4 Feb 2007
    Messages:
    1,006
    Likes Received:
    444
    Reputations:
    94
    >>где в своих постах я использовал данный термин не "по назначению".

    Один алгоритм (или "способ решения") к классу задач нельзя применить. Класс задач лишь говорит, что например, заача решается за полиномиальное время. Но если за полиномиальное время можно и посадить картошку, и собрать яблоки - это не значит, что это делается одним и тем же способом.

    тут под классом задач, как я понимаю, имеется в виду "похожие по смыслу задачи". А, например, для похожих по смыслу задач проверки числа на простоту (невероятностного) и разложения на множители, первая имеет быстрое решение (логарифм числа в какой-то степени), а про вторую существование быстрого решения неизвестно.

    >>которых вполне достаточно для сравнения алгоритмов по эффективности.
    недостаточно. Вот почему, по-вашему, так часто пишут qsort, хотя худший случай это N^2, а не merge - с N log N ? А потому что, очень часто (читай - на случайном входе) быстродействие первого оказывается не хуже второго, а часто - лучше.
     
  16. Nikituki

    Nikituki New Member

    Joined:
    14 Mar 2009
    Messages:
    19
    Likes Received:
    3
    Reputations:
    0
    Для алгоритмов, уже описанных в этом топике, оценка среднего случая не так важна, тк в каждом из них она ближе к худшему случаю.
    А о сортировках из вашего примера (быстрой и слиянием) автор еще не упоминал, и я уверен, что когда он это сделает, то мы увидим оценку их временной сложности в среднем случае ;)
     
    1 person likes this.
  17. ErrorNeo

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    Кнута не читал и пока не собираюсь.
    Эта статья интерсна, и чем больше в ней ставрительных характеристик тем лучше.
    Если будут выкладки из чего-либо кроме википедии - будет вообще perfect;)
     
  18. c0n Difesa

    c0n Difesa Member

    Joined:
    1 Jan 2009
    Messages:
    133
    Likes Received:
    66
    Reputations:
    18
    Под классом задач тут понимается именно похожие по сложности задачи. Например схожие по размеру и степени упорядоченности массивы.

    Приведенные Вами алгоритмы сортировок я еще не успел рассмотреть. Повторюсь еще раз (и как заметил, Nikituki): в уже рассмотренных алгоритмах средний случай эквивалентен худшему. Ваше замечание я учту в дальнейших обзорах и средний случай буду рассматривать отдельно.
    Будет еще замечательней, если другие также будут выкладывать свои алгоритмы (не только базовые, коих хватает в Википедии) с их обзорами. ;)
     
  19. Nikituki

    Nikituki New Member

    Joined:
    14 Mar 2009
    Messages:
    19
    Likes Received:
    3
    Reputations:
    0
    Циклический сдвиг элементов массива вправо на k позиций

    Ну чтож, попробую, мб кому-нибудь пригодится=)

    Циклический сдвиг элементов массива вправо на k позиций​

    1) Код:
    Code:
    template <typename MassiveType>
    void Shift(MassiveType *Massive, int MassiveLen, int k)
    { 	
            Reverse(Massive,0,MassiveLen-1); //разворачиваем массив   
            Reverse(Massive,0,k-1);  //разворачиваем первые к элементов
    	Reverse(Massive,k,MassiveLen-1); //разворачиваем последние n-k эллементов
    }
    
    template <typename MassiveType>
    void Reverse(MassiveType *Massive, int StartElem, int FinishElem)
    { 	
            int i;
            MassiveType tresh; 	
            for (i=0;i<=(FinishElem-StartElem)/2;i++) 
            {
                      tresh=Massive[StartElem+i]; 	 
                      Massive[StartElem+i]=Massive[FinishElem-i]; 		       
                      Massive[FinishElem-i]=tresh; 	
            } 
    }
    2) Особенности:

    Не используется выделение больших объемов дополнительной памяти.

    3) Временная сложность:

    Во всех случаях Т(n) = О(N)
     
    #19 Nikituki, 19 Oct 2009
    Last edited: 19 Oct 2009