1. Java / Говнокод #7711

    +76

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    public class Sorting {  
    
        private static void swapElements(int[] arr, int index1, int index2) {
            int temp = arr[index1];
            arr[index1] = arr[index2];
            arr[index2] = temp;
        }
    
        public static void mergeSort(int[] arr) {
            if (arr.length == 1) {
                return;
            }        
            final int temp = (arr.length % 2 == 0) ? arr.length / 2 : (arr.length + 1) / 2;
    
            int[] left = new int[temp];
            int[] right = new int[arr.length / 2];
            System.arraycopy(arr, 0, left, 0, temp);
            System.arraycopy(arr, temp, right, 0, arr.length / 2);
    
            Sorting.mergeSort(left);
            Sorting.mergeSort(right);
            Sorting.mergeSortHelper(arr, left, right);
        }
    
        private static void mergeSortHelper(int[] arr, int[] left, int[] right) {
            int L = 0, R = 0;
            boolean Ltop = false, Rtop = false;
    
            for (int i = 0; i < arr.length; i++) {
                if (L < left.length - 1 && R < right.length - 1) {
                    if (left[L] <= right[R]) {
                        arr[i] = left[L];
                        L++;
                    } else {
                        arr[i] = right[R];
                        R++;
                    }
                } else if ((L == left.length - 1) ^ (R == right.length - 1)) {
                    if (L == left.length - 1) {
                        if ((left[L] <= right[R]) && !Ltop) {
                            arr[i] = left[L];
                            Ltop = true;
                        } else {                        
                            arr[i] = right[R];
                            R++;
                        }
                    } else {
                        if ((right[R] <= left[L]) && !Rtop) {
                            arr[i] = right[R];
                            Rtop = true;
                        } else {                        
                            arr[i] = left[L];
                            L++;
                        }
                    }
                } else {
                    if (i < arr.length - 1) {
                        arr[i] = (left[L] < right[R]) ? left[L] : right[R];                    
                    } else {                    
                        arr[i] = (left[L] > right[R]) ? left[L] : right[R];
                    }
                }
            }        
        }

    Реализация сортировки слиянием на Java

    Запостил: kaspvar, 31 Августа 2011

    Комментарии (43) RSS

    • Сразу много вопросов:
      1. Зачем?
      2. Почему так много?
      3. Где дженерики? -> Где здесь java?
      Ответить
    • 1. Знать элементарные алгоритмы сортировки нужно обязательно.
      2. Я б-кодер =(
      3. До дженериков еще не дошел.
      Ответить
    • Почему бы не сделать так:
      final int temp = (arr.length + 1) / 2;
      
              int[] left = new int[temp];
              int[] right = new int[arr.length - temp];
      И не переименовать temp в middle?
      И весь mergeSortHelper сомнителен, особенно название, else if и bool'и в нем.
      Ответить
      • К тому же, есть Arrays:
        final int middle = (arr.length + 1) / 2;
        int[] left  = Arrays.copyOfRange(arr, 0, middle);
        int[] right = Arrays.copyOfRange(arr, middle + 1, arr.length);
        Ответить
    • Ни разу не видел нормального кода слияния массивов. Действие, казалось бы, тривиальное,, но его алгоритм всегда выглядит, как говно, с тройными неинтуитивными условиями и причей фигнёй.
      Ответить
      • (defun stupid-merge-sort (seq)
            (if (< (length seq) 2)
                seq
                (let (
                    (middle (truncate (length seq) 2)))
                    (merge (if (listp seq) `list `vector) (stupid-merge-sort (subseq seq 0 middle)) (stupid-merge-sort (subseq seq middle)) #'<))))
        Ня?
        Ответить
        • Так не честно, всё самое интересное уползло в библиотечную merge. С другой стороны, реализовать её довольно просто.
          Ответить
          • честно =)
            mSort([],[]):-!.
            mSort([X],[X]):-!.
            mSort(X,Y):-split(X,H,T),mSort(H,H1),mSort(T,T1),merge(H1,T1,Y).
            
            merge([],X,X):-!.
            merge(X,[],X):-!.
            merge([H1|X],[H2|Y],[H1|R]):- H1 < H2,!,merge(X,[H2|Y],R).
            merge(X,[H2|Y],[H2|R]):- merge(X,Y,R).
            split(X,H,T):- length(X,LenX),append(H,T,X),length(H,LenH),LenH is div(LenX,2).
            Ответить
            • язык смайликов?
              Ответить
              • На прологе самое то решать дурацкие задачки.
                Ни ifов ни циклов тебе.
                Ответить
                • Мне haskell нравиться (код писал не я, но я бы написал так же):
                  merge [] ys = ys
                  merge xs [] = xs
                  merge (x:xs) (y:ys) = if x <= y
                                        then x : merge xs (y:ys)
                                        else y : merge (x:xs) ys
                  
                  mergesort [] = []
                  mergesort [x] = [x]
                  mergesort xs = let (as, bs) = splitAt (length xs `quot` 2) xs
                                 in merge (mergesort as) (mergesort bs)
                  Ответить
                  • P.S. Хотя нет, третий шаблон для merge надо бы написать по-другому:
                    merge u@(x:xs) v@(y:ys) = if x <= y
                                              then x : merge xs v
                                              else y : merge u ys
                    Ответить
                    • ждём решения на Forth
                      Ответить
                      • На Форте не нашел, но есть на самом любимом языке Тараса:
                        #include        <iterator>
                        #include        <utility>
                        #include        <algorithm>
                        
                        #include        <deque>
                        #include        <string>
                        #include        <iostream>
                        
                        template <typename SomeIterator, typename SomeCompare>
                            void stupid_merge_sort(SomeIterator begin, SomeIterator end, SomeCompare compare, std::bidirectional_iterator_tag category){
                        
                            typename SomeIterator::difference_type distance = std::distance(begin, end);
                        
                            if((distance > 2) || (distance < -2)){
                                SomeIterator middle = begin;
                                std::advance(middle, distance/2);
                                stupid_merge_sort(begin, middle, compare,  category);
                                stupid_merge_sort(middle, end, compare, category);
                                std::inplace_merge(begin, middle, end, compare);
                            }
                        }
                        
                        template <typename SomeIterator>
                            void stupid_merge_sort(SomeIterator begin, SomeIterator end){
                                stupid_merge_sort(begin, end, std::less<typename SomeIterator::value_type>(), typename std::iterator_traits<SomeIterator>::iterator_category());
                        }
                        
                        template <typename SomeIterator, typename SomeCompare>
                            void stupid_merge_sort(SomeIterator begin, SomeIterator end, SomeCompare compare = SomeCompare()){
                                stupid_merge_sort(begin, end, compare, typename std::iterator_traits<SomeIterator>::iterator_category());
                        }
                        
                        typedef std::deque<std::string> SomeContainer;
                        
                        int main(int argc, char* argv[]){
                            SomeContainer       cont;
                        
                            for(unsigned i = 1; i < argc; i++)
                                cont.push_back(SomeContainer::value_type(argv[i]));
                        
                            stupid_merge_sort(cont.begin(), cont.end());
                        
                            for(SomeContainer::iterator it = cont.begin(); it != cont.end(); ++it)
                                std::cout<<(*it)<<std::endl;
                        }
                        Ответить
                      • Лёгкое гугление даёт такой результат:
                        : merge-step ( right mid left -- right mid+ left+ )
                          over @ over @ < if
                            over @ >r
                            2dup - over dup cell+ rot move
                            r> over !
                            >r cell+ 2dup = if rdrop dup else r> then
                          then cell+ ;
                        : merge ( right mid left -- right left )
                          dup >r begin 2dup > while merge-step repeat 2drop r> ;
                         
                        : mid ( l r -- mid ) over - 2/ cell negate and + ;
                         
                        : mergesort ( right left -- right left )
                          2dup cell+ <= if exit then
                          swap 2dup mid recurse rot recurse merge ;
                         
                        : sort ( addr len -- )  cells over + swap mergesort 2drop ;
                         
                        create test 8 , 1 , 5 , 3 , 9 , 0 , 2 , 7 , 6 , 4 ,
                         
                        : .array ( addr len -- ) 0 do dup i cells + @ . loop drop ;
                         
                        test 10 2dup sort .array       \ 0 1 2 3 4 5 6 7 8 9
                        Ответить
                  • я как-то на эрланге пытался это написать в качестве упражнения. получилось не упражнение - а испражнение. не выдержал поглядел как делать правильно - а там такое же испражнение.

                    отсутствие структур данных высокого порядка портит ИМО функциональные языки. уперлись ж религиозно в односвязные списки...
                    Ответить
                    • Что имеется ввиду под структурами данных высшего порядка?
                      Ответить
                    • Не знаю, как в Erlang (он следующий в моей очереди на изучение), но в стандартную библиотеку Haskell входят массивы, бинарные строки, деревья, графы, хэш-таблицы и ещё много всего (разумеется, вместе со стандартными алгоритмами). Неужели всего этого нет в Erlang?
                      Ответить
                      • есть. но большинство реализовано на самом эрланге обычными списками.

                        когда видишь обычную FIFO у которой ассимптотическая производительность O(n) (best case O(1), но в случае FIFO это просто не случается, cue in zippers) то как подталкивает на размышления.
                        Ответить
                        • На том же Lisp на списках легко делается FIFO с асимптотической сложностью O(1). Странно всё это.
                          Ответить
                          • в лисп? FIFO без зипперов? пример в студию: добавление элемента в конец, удаление из начала, оба O(1). (я по лиспу книжку читаю, интересно.)
                            Ответить
                            • Может, я чего-то не понимаю... просветите. Вот каноническая книжка с описанием реализации очереди без приоритетов:
                              http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec_3.3.2
                              Ответить
                              • реализация использует cdr, который возвращает все элементы массива кроме первого, на основе чего создается новый список -> происходит копирование почти полного списка -> O(N).

                                нету в функциональных языках O(1) оператора для добавления элемента в конец списка.

                                единственное что придумали это зипперы - http://en.wikipedia.org/wiki/Zipper_%28data_structure%29 - но они предоставляют только амортизированую O(1).
                                Ответить
                                • > происходит копирование почти полного списка
                                  кто вам такое сказал? можно ссылку на источник? конструирование происходит только с помощью cons (и это операция O(1)), car и cdr - просто селекторы. Они нужны для обхода списка и никоим образом его не модифицируют (разве что только могут появиться объекты, пригодные для сборки мусора). Там же написано: "the queue operations to be implemented so that they require O(1) steps".
                                  Ответить
                                  • ты похоже прав. я еще тольком с лисповыми переменными не разобрался: они ведь в отличии от хаскеля и эрланга mutable. то что я говорил 100% применимо к эрлангу и если я не ошибаюсь к хаскелю - или обобщенно к языками которые стремятся быть чисто функциональными.
                                    Ответить
                                    • Да, в haskell значения переменных и списки менять нельзя и там такую очередь не напишешь (нельзя будет изменить конец в очереди как в lisp). Там это и не нужно, ибо есть Data.Sequence (чисто функциональный, сорцы можно посмотреть в интернете).
                                      Ответить
                                      • видел. Data.Sequence это finger tree (пальчиковое дерево? лол) работают по принципу подобному zipper, но для организации так же используют lazy evaluation. вообщем: тоже предоставляют только амортизированое время.

                                        лисп из всех этих языков наверное самый мощный, бо не пытается красивым теориям следовать, а остается просто практичным.

                                        эрланг так же своей практичностью привлекателен (тем более что я работаю в телекомах) но вот той функциональной фигней, и тем что надо рано начинать думать о производительности (и не только о проце - но так же и о памяти) напрягает.

                                        на хаскель после прочтения пару туториалов я забил, бо очень много теории и сказок о красоте программирования на хаскеле. субстанции очень мало.

                                        а ведь все началась с простого поиска выразительного язычка для быстрого прототипирования...
                                        Ответить
                                        • > выразительного язычка для быстрого прототипирования
                                          python?

                                          Если бы Erlang был не функциональным, его модель акторов была бы в глубокой... яме.

                                          Так-то я пишу на Java. Haskell изучаю ради новых идей... И чтобы свободнее себя чувствовать в Scala. Мне он кажется довольно практичным, но на освоение требуется уйма времени и практики. Хотя Lisp тоже доставляет. Жаль, времени мало на всё.
                                          Ответить
                                          • > python?

                                            отсутствие варнингов + слабая типизация + общая тормознутость не самая лучшая комбинация, к сожалению.

                                            перл иногда тормозит похлеще, но варнинги (что я может чего не то написал что я думал что я написал) кидает сразу. количество встроеных прямо в язык функций тоже как бы развращает: можно по тупому сложные (но вторичные) проблемы делать.

                                            с перлом моя проблема только в том что иногда напишешь прототип, вроде коротко и работает нормально. а когда начинаешь это в С/С++ конвертить... страницы и страницы кода. эстимэйшены времени разработки на основе перловых прототипов делать в принципе невозможно.
                                            Ответить
                                            • Код с Lisp/Erlang конвертить в C/C++ вроде бы вообще задача нетривиальная... C Perl то уж попроще будет. По статистике программа на Perl в 8-10 раз короче программы на C, программа на C++ - в 2 раза короче аналогичной программы на C (так написано у Макконнелла). Вот вам и эстимэйшн :) Конечно, многое ещё зависит от программиста.
                                              Ответить
                            • > я по лиспу книжку читаю
                              какую, если не секрет?
                              Ответить
            • > merge([],X,X):-!.
              А так вообще можно? В смысле, одинаковое имя аргументов.
              Ответить
              • да это означает что если мы мерджим пустой список с X то результат будет X.
                Синтерпретировано в Swi-Prolog
                Ответить
        • > кода слияния массивов
          Ответить
          • (merge <что-то> <кое-что> <что-нибудь> <предикат>)
            Вполне себе код слияния массивов (точнее proper sequences)
            Ответить
        • вот вам на перле самописаное кахдато давно:
          sub merge_sort
          {
          	my ($cmp, @l) = @_;
          
          	return @l if @l <= 1;
          
          	my @l1 = merge_sort( $cmp, @l[0..$#l/2] );
          	my @l2 = merge_sort( $cmp, @l[$#l/2+1 .. $#l] );
          
          	my @ret;
          	while (@l1 && @l2) {
          		if ($cmp->($l1[0], $l2[0])) {
          			push @ret, shift(@l1);
          		} else {
          			push @ret, shift(@l2);
          		}
          	}
          
          	push @ret, @l1 if @l1;
          	push @ret, @l2 if @l2;
          	@ret;
          }
          
          print merge_sort( sub { $_[0] lt $_[1] }, <> );


          неоптимально, ну да и хер с ним. писал только что бы узнать сколько приблизительно строк (по сравнение с С вариантом) на Перле будет.
          Ответить
    • Кому интересно посмотреть, как это сделано в java.util: http://www.docjar.com/docs/api/java/util/DualPivotQuicksort.html
      Ответить
      • я бумажку по дуал пайвоту качнул но еще не читал. но выглядит так как если бы всех проблем qsort он не решает, а только уменьшает вероятность деградации производительности.

        другими словами: везде где важна ассимптотическая (не абсолютная!) производительность, все равно надо мерж сорт писать.
        Ответить
    • показать все, что скрытоПОНИ ПРОСРАЛИ!
      Ответить
      • http://i3.photobucket.com/albums/y81/Panther631/ModsAreAsleepPostPonies_6433.jpg ?

        на ГК не пройдет.
        Ответить
    • показать все, что скрытоvanished
      Ответить

    Добавить комментарий