ツリーソート

ツリーソート – 二分探索ツリーを使用したソート。時間計算量 – O(n²)。このようなツリーでは、左側の各ノードにはノードより小さい番号があり、右側にはノードより大きい番号があります。ルートから来て左から右に値を出力すると、ソートされた番号のリストが得られます。 。驚くべきことですね?

二分探索ツリー図を考えてみましょう。

デリック・クッツェー (パブリック ドメイン)

左下の各ノード、つまり右側のノードごとに、左下隅の最後から 2 番目の左ノードから数字を手動で読み取ってみてください。

次のようになります:

<オル>

  • 左下の最後から2番目のノード – 3.
  • 左分岐があります – 1.
  • この番号 (1) を選択してください
  • 次に頂点 3 (1, 3) を取得します
  • 右側はブランチ 6 ですが、ブランチが含まれています。したがって、同じように読みます。
  • ノード 6 の左分岐 4 (1、3、4)
  • ノード自体は 6 (1、3、4、6) です
  • 右 7 (1、3、4、6、7)
  • ルート ノードに移動します – 8 (1、3、4、6、7、8)
  • 類推により、右側にすべてを出力します
  • 最終的なリストを取得します – 1、3、4、6、7、8、10、13、14
  • コードでアルゴリズムを実装するには、次の 2 つの関数が必要です。

    <オル>

  • 二分探索ツリーの組み立て
  • 二分探索ツリーを正しい順序で出力する
  • 二分探索木は読み取られたときと同じ方法で組み立てられ、それが大きいか小さいかに応じて、左側または右側の各ノードに番号が付けられます。

    Lua での例:

    
    function Node:new(value, lhs, rhs)
        output = {}
        setmetatable(output, self)
        self.__index = self  
        output.value = value
        output.lhs = lhs
        output.rhs = rhs
        output.counter = 1
        return output  
    end
    
    function Node:Increment()
        self.counter = self.counter + 1
    end
    
    function Node:Insert(value)
        if self.lhs ~= nil and self.lhs.value > value then
            self.lhs:Insert(value)
            return
        end
    
        if self.rhs ~= nil and self.rhs.value < value then
            self.rhs:Insert(value)
            return
        end
    
        if self.value == value then
            self:Increment()
            return
        elseif self.value > value then
            if self.lhs == nil then
                self.lhs = Node:new(value, nil, nil)
            else
                self.lhs:Insert(value)
            end
            return
        else
            if self.rhs == nil then
                self.rhs = Node:new(value, nil, nil)
            else
                self.rhs:Insert(value)
            end
            return
        end
    end
    
    function Node:InOrder(output)
        if self.lhs ~= nil then
           output = self.lhs:InOrder(output)
        end
        output = self:printSelf(output)
        if self.rhs ~= nil then
            output = self.rhs:InOrder(output)
        end
        return output
    end
    
    function Node:printSelf(output)
        for i=0,self.counter-1 do
            output = output .. tostring(self.value) .. " "
        end
        return output
    end
    
    function PrintArray(numbers)
        output = ""
        for i=0,#numbers do
            output = output .. tostring(numbers[i]) .. " "
        end    
        print(output)
    end
    
    function Treesort(numbers)
        rootNode = Node:new(numbers[0], nil, nil)
        for i=1,#numbers do
            rootNode:Insert(numbers[i])
        end
        print(rootNode:InOrder(""))
    end
    
    
    numbersCount = 10
    maxNumber = 9
    
    numbers = {}
    
    for i=0,numbersCount-1 do
        numbers[i] = math.random(0, maxNumber)
    end
    
    PrintArray(numbers)
    Treesort(numbers)

    Важный нюанс что для чисел которые равны вершине придумано множество интересных механизмов подцепления к ноде, я же просто добавил счетчик к классу вершины, при распечатке числа возвращаются по счетчику.

    Ссылки

    https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/treesort

    Источники

    TreeSort Algorithm Explained and Implemented with Examples in Java | Sorting Algorithms | Geekific – YouTube

    Tree sort – YouTube

    Convert Sorted Array to Binary Search Tree (LeetCode 108. Algorithm Explained) – YouTube

    Sorting algorithms/Tree sort on a linked list – Rosetta Code

    Tree Sort – GeeksforGeeks

    Tree sort – Wikipedia

    How to handle duplicates in Binary Search Tree? – GeeksforGeeks

    Tree Sort | GeeksforGeeks – YouTube

    バケットソート

    バケット並べ替え – バケットごとに並べ替えます。このアルゴリズムはカウンティングソートに似ていますが、数値が「バケット」範囲に収集され、その後、他の十分に生産性の高いソートアルゴリズムを使用してバケットがソートされ、最後のステップで「バケット」の範囲が展開される点が異なります。 1 ずつ増やすと、ソートされたリストが得られます。

    アルゴリズムの時間計算量は O(nk) です。このアルゴリズムは、一様分布の法則に従うデータに対して線形時間で機能します。簡単に言うと、要素は「スパイク」のない特定の範囲内にある必要があります (たとえば、0.0 から 1.0 までの数値)。そのような数字の中に 4 または 999 がある場合、中庭法によれば、そのような列は「偶数」とみなされなくなります。

    Julia での実装例:

        buckets = Vector{Vector{Int}}()
        
        for i in 0:bucketsCount - 1
            bucket = Vector{Int}()
            push!(buckets, bucket)
        end
    
        maxNumber = maximum(numbers)
    
        for i in 0:length(numbers) - 1
            bucketIndex = 1 + Int(floor(bucketsCount * numbers[1 + i] / (maxNumber + 1)))
            push!(buckets[bucketIndex], numbers[1 + i])
        end
    
        for i in 0:length(buckets) - 1
            bucketIndex = 1 + i
            buckets[bucketIndex] = sort(buckets[bucketIndex])
        end
    
        flat = [(buckets...)...]
        print(flat, "\n")
    
    end
    
    numbersCount = 10
    maxNumber = 10
    numbers = rand(1:maxNumber, numbersCount)
    print(numbers,"\n")
    bucketsCount = 10
    bucketSort(numbers, bucketsCount)

    На производительность алгоритма также влияет число ведер, для большего количества чисел лучше взять большее число ведер (Algorithms in a nutshell by George T. Heineman)

    Ссылки

    https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/bucketSort

    Источники

    https://www.youtube.com/watch?v=VuXbEb5ywrU
    https://www.youtube.com/watch?v=ELrhrrCjDOA
    https://medium.com/karuna-sehgal/an-introduction-to-bucket-sort-62aa5325d124
    https://www.geeksforgeeks.org/bucket-sort-2/
    https://ru.wikipedia.org/wiki/%D0%91%D0%BB%D0%BE%D1%87%D0%BD%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0
    https://www.youtube.com/watch?v=LPrF9yEKTks
    https://en.wikipedia.org/wiki/Bucket_sort
    https://julialang.org/
    https://www.oreilly.com/library/view/algorithms-in-a/9780596516246/ch04s08.html

    基数ソート

    基数ソート – 基数ソート。このアルゴリズムは、要素の比較がないという点でカウント ソートに似ています。代わりに、要素が *文字ごと* に *バケット* (バケット) にグループ化され、バケットは現在の数値文字のインデックスによって選択されます。時間計算量 – O(nd)。

    次のように動作します:

    • 入力は数字 6、12、44、9 になります
    • リスト (0 ~ 9) のバケットを 10 個作成し、そこに少しずつ数字を追加/並べ替えます。

    次へ:

    <オル>

  • 数値内の最大文字数までのカウンター i でループを開始します
  • インデックス i を右から左に指定すると、各数値に対して 1 つの記号が得られ、記号がない場合は 0 であると見なされます。
  • 記号を数値に変換する
  • インデックス番号でバケットを選択し、そこに整数を入力します
  • 数値の検索が終了したら、すべてのバケットを数値のリストに変換し直します
  • ランク順に並べ替えられた数値を取得する
  • すべての数字がなくなるまで繰り返します
  • Scala での基数ソートの例:

    
    import scala.util.Random.nextInt
    
    
    
    object RadixSort {
    
        def main(args: Array[String]) = {
    
            var maxNumber = 200
    
            var numbersCount = 30
    
            var maxLength = maxNumber.toString.length() - 1
    
    
    
            var referenceNumbers = LazyList.continually(nextInt(maxNumber + 1)).take(numbersCount).toList
    
            var numbers = referenceNumbers
    
            
    
            var buckets = List.fill(10)(ListBuffer[Int]())
    
    
    
            for( i <- 0 to maxLength) { numbers.foreach( number => {
    
                        var numberString = number.toString
    
                        if (numberString.length() > i) {
    
                            var index = numberString.length() - i - 1
    
                            var character = numberString.charAt(index).toString
    
                            var characterInteger = character.toInt  
    
                            buckets.apply(characterInteger) += number
    
                        }
    
                        else {
    
                            buckets.apply(0) += number
    
                        }
    
                    }
    
                )
    
                numbers = buckets.flatten
    
                buckets.foreach(x => x.clear())
    
            }
    
            println(referenceNumbers)
    
            println(numbers)
    
            println(s"Validation result: ${numbers == referenceNumbers.sorted}")
    
        }
    
    }
    
    

    このアルゴリズムには、GPU などで並列実行するためのバージョンもあります。ちょっとした並べ替えオプションもあります。これは非常に興味深く、本当に息をのむようなものに違いありません。

    リンク

    https://gitlab .com/demensdeum/algorithms/-/blob/master/sortAlgorithms/radixSort/radixSort.scala

    ソース

    https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%80%D0%B0%D0%B7%D1%80%D1%8F%D 0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0% BA%D0%B0
    https://www.geeksforgeeks.org/radix-sort/

    https://www.youtube.com/watch?v=toAlAJKojos

    https://github.com/gyatskov/radix-sort

    ヒープソート

    ヒープソート – ピラミッドソート。アルゴリズムの時間計算量 – O(n log n)、速いですよね?私はこれを、落ちてくる小石の選別と呼んでいます。これを説明する最も簡単な方法は視覚的に説明することだと思います。

    入力は、次のような数値のリストです。
    5、0、7、2、3、9、4

    左から右に、データ構造、つまりバイナリ ツリー、または私がそれを呼んでいる – が作成されます。ピラミッド。ピラミッド要素には最大 2 つの子要素を含めることができますが、最上位の要素は 1 つだけです。

    バイナリ ツリーを作成しましょう:
    ⠀⠀5
    ⠀0⠀7
    2 3 9 4

    ピラミッドを長い間見てみると、これらは配列からの単なる数値であり、次々に来て、各フロアの要素の数が 2 倍になっていることがわかります。

    次に、楽しい作業が始まります。小石を落とす方法 (heapify) を使用して、ピラミッドを下から上に並べ替えましょう。最終階(2 3 9 4)から並べ替えを開始することもできますが、意味がありません。以下に転落する可能性のある床はありません。

    したがって、最後から 2 番目のフロア (0 7) から要素をドロップし始めます。
    ⠀⠀5
    ⠀0⠀7
    2 3 9 4

    最初に該当する要素が右から選択されます。この場合は 7 です。次に、その下にあるものを調べます。その下には 9 と 4 があり、9 は 4 より大きく、9 はより大きいです。セブン! 7 を 9 に落とし、9 を持ち上げて 7 の位置に置きます。
    ⠀⠀5
    ⠀0⠀9
    2 3 7 4

    次に、7 には下に落ちるところがないことがわかり、左側の最後から 2 番目の階にある番号 0 に進みます。
    ⠀⠀5
    0⠀9
    2 3 7 4

    その下にあるものを見てみましょう – 2 と 3、2 は 3 より小さく、3 は 0 より大きいので、0 と 3 を交換します。
    ⠀⠀5
    ⠀3⠀9
    2 0 7 4

    フロアの端に到達したら、上のフロアに行き、可能であればそこにすべてを落としてください。
    結果はデー​​タ構造、つまりヒープ、つまり最大ヒープになります。一番上にあるのは最大の要素です。
    ⠀⠀9
    ⠀3⠀7
    2 0 5 4

    これを配列表現に戻すと、リストが得られます。
    [9、3、7、2、0、5、4]

    このことから、最初と最後の要素を交換することで、最終的な並べ替え位置の最初の数値が得られる、つまり 9 が並べ替えられたリストの最後にあるはずであると結論付けることができ、場所を入れ替えます。
    [4、3、7、2、0、5、9]

    二分木を見てみましょう:
    ⠀⠀4
    ⠀3⠀7
    2 0 5 9

    結果は、ツリーの下の部分がソートされた状況になります。必要なのは、4 を正しい位置にドロップし、アルゴリズムを繰り返すだけです。ただし、すでにソートされている数値、つまり 9 は考慮しません。
    ⠀⠀4
    ⠀3⠀7
    2 0 5 9

    ⠀⠀7
    ⠀3⠀4
    2 0 5 9

    ⠀⠀7
    ⠀3⠀5
    2 0 4 9

    4 を落とした後、9 – の次に大きな数字を上げたことが判明しました。 7. ソートされていない最後の数字 (4) と最大の数字 (7) を交換します
    ⠀⠀4
    ⠀3⠀5
    2 0 7 9

    正しい最終位置に 2 つの数値があることがわかりました。
    4、3、5、2、0、79

    次に、既に並べ替えられたアルゴリズムを無視して並べ替えアルゴリズムを繰り返します。最終的には ヒープ タイプ:
    ⠀⠀0
    ⠀2⠀3
    4 5 7 9

    またはリストとして:
    0、2、3、4、5、7、9

    実装

    アルゴリズムは通常、次の 3 つの機能に分割されます。

    <オル>

  • ヒープの作成
  • ふるい分けアルゴリズム (heapify)
  • ソートされていない最後の要素と最初の要素を置き換えます
  • ヒープは、heapify 関数を使用してバイナリ ツリーの最後から 2 番目の行を右から左に配列の末尾まで走査することによって作成されます。次にサイクルでは、最初の数値の置換が行われ、その後、最初の要素が配置されるか、その位置に残ります。その結果、最大の要素が 1 位に配置され、参加者が 1 人減ってサイクルが繰り返されます。各パスの後、ソートされた数値がリストの最後に残ります。

    Ruby でのヒープソートの例:

    
    
    
    
    
    module Colors
    
    
    
        BLUE = "\033[94m"
    
    
    
        RED = "\033[31m"
    
    
    
        STOP = "\033[0m"
    
    
    
    end
    
    
    
    
    
    
    
    def heapsort(rawNumbers)
    
    
    
        numbers = rawNumbers.dup
    
    
    
    
    
    
    
        def swap(numbers, from, to)
    
    
    
            temp = numbers[from]
    
    
    
            numbers[from] = numbers[to]
    
    
    
            numbers[to] = temp
    
    
    
        end
    
    
    
    
    
    
    
        def heapify(numbers)
    
    
    
            count = numbers.length()
    
    
    
            lastParentNode = (count - 2) / 2
    
    
    
    
    
    
    
            for start in lastParentNode.downto(0)
    
    
    
                siftDown(numbers, start, count - 1)
    
    
    
                start -= 1 
    
    
    
            end
    
    
    
    
    
    
    
            if DEMO
    
    
    
                puts "--- heapify ends ---"
    
    
    
            end
    
    
    
        end
    
    
    
    
    
    
    
        def siftDown(numbers, start, rightBound)      
    
    
    
            cursor = start
    
    
    
            printBinaryHeap(numbers, cursor, rightBound)
    
    
    
    
    
    
    
            def calculateLhsChildIndex(cursor)
    
    
    
                return cursor * 2 + 1
    
    
    
            end
    
    
    
    
    
    
    
            def calculateRhsChildIndex(cursor)
    
    
    
                return cursor * 2 + 2
    
    
    
            end            
    
    
    
    
    
    
    
            while calculateLhsChildIndex(cursor) <= rightBound
    
    
    
                lhsChildIndex = calculateLhsChildIndex(cursor)
    
    
    
                rhsChildIndex = calculateRhsChildIndex(cursor)
    
    
    
    
    
    
    
                lhsNumber = numbers[lhsChildIndex]
    
    
    
                biggerChildIndex = lhsChildIndex
    
    
    
    
    
    
    
                if rhsChildIndex <= rightBound
    
    
    
                    rhsNumber = numbers[rhsChildIndex]
    
    
    
                    if lhsNumber < rhsNumber
    
    
    
                        biggerChildIndex = rhsChildIndex
    
    
    
                    end
    
    
    
                end
    
    
    
    
    
    
    
                if numbers[cursor] < numbers[biggerChildIndex]
    
    
    
                    swap(numbers, cursor, biggerChildIndex)
    
    
    
                    cursor = biggerChildIndex
    
    
    
                else
    
    
    
                    break
    
    
    
                end
    
    
    
                printBinaryHeap(numbers, cursor, rightBound)
    
    
    
            end
    
    
    
            printBinaryHeap(numbers, cursor, rightBound)
    
    
    
        end
    
    
    
    
    
    
    
        def printBinaryHeap(numbers, nodeIndex = -1, rightBound = -1)
    
    
    
            if DEMO == false
    
    
    
                return
    
    
    
            end
    
    
    
            perLineWidth = (numbers.length() * 4).to_i
    
    
    
            linesCount = Math.log2(numbers.length()).ceil()
    
    
    
            xPrinterCount = 1
    
    
    
            cursor = 0
    
    
    
            spacing = 3
    
    
    
            for y in (0..linesCount)
    
    
    
                line = perLineWidth.times.map { " " }
    
    
    
                spacing = spacing == 3 ? 4 : 3
    
    
    
                printIndex = (perLineWidth / 2) - (spacing * xPrinterCount) / 2
    
    
    
                for x in (0..xPrinterCount - 1)
    
    
    
                    if cursor >= numbers.length
    
    
    
                        break
    
    
    
                    end
    
    
    
                    if nodeIndex != -1 && cursor == nodeIndex
    
    
    
                        line[printIndex] = "%s%s%s" % [Colors::RED, numbers[cursor].to_s, Colors::STOP]
    
    
    
                    elsif rightBound != -1 && cursor > rightBound
    
    
    
                        line[printIndex] = "%s%s%s" % [Colors::BLUE, numbers[cursor].to_s, Colors::STOP]
    
    
    
                    else
    
    
    
                        line[printIndex] = numbers[cursor].to_s
    
    
    
                    end
    
    
    
                    cursor += 1
    
    
    
                    printIndex += spacing
    
    
    
                end
    
    
    
                print line.join()
    
    
    
                xPrinterCount *= 2           
    
    
    
                print "\n"            
    
    
    
            end
    
    
    
        end
    
    
    
    
    
    
    
        heapify(numbers)
    
    
    
        rightBound = numbers.length() - 1
    
    
    
    
    
    
    
        while rightBound > 0
    
    
    
            swap(numbers, 0, rightBound)   
    
    
    
            rightBound -= 1
    
    
    
            siftDown(numbers, 0, rightBound)     
    
    
    
        end
    
    
    
    
    
    
    
        return numbers
    
    
    
    end
    
    
    
    
    
    
    
    numbersCount = 14
    
    
    
    maximalNumber = 10
    
    
    
    numbers = numbersCount.times.map { Random.rand(maximalNumber) }
    
    
    
    print numbers
    
    
    
    print "\n---\n"
    
    
    
    
    
    
    
    start = Time.now
    
    
    
    sortedNumbers = heapsort(numbers)
    
    
    
    finish = Time.now
    
    
    
    heapSortTime = start - finish
    
    
    
    
    
    
    
    start = Time.now
    
    
    
    referenceSortedNumbers = numbers.sort()
    
    
    
    finish = Time.now
    
    
    
    referenceSortTime = start - finish
    
    
    
    
    
    
    
    print "Reference sort: "
    
    
    
    print referenceSortedNumbers
    
    
    
    print "\n"
    
    
    
    print "Reference sort time: %f\n" % referenceSortTime
    
    
    
    print "Heap sort:      "
    
    
    
    print sortedNumbers
    
    
    
    print "\n"
    
    
    
    if DEMO == false
    
    
    
        print "Heap sort time:      %f\n" % heapSortTime
    
    
    
    else
    
    
    
        print "Disable DEMO for performance measure\n"
    
    
    
    end
    
    
    
    
    
    
    
    if sortedNumbers != referenceSortedNumbers
    
    
    
        puts "Validation failed"
    
    
    
        exit 1
    
    
    
    else
    
    
    
        puts "Validation success"
    
    
    
        exit 0
    
    
    
    end
    
    
    
    

    このアルゴリズムは視覚化しないと理解しにくいため、最初にバイナリ ツリーの現在のビューを出力する関数を作成することをお勧めします。

    リンク

    https://gitlab.com/demensdeum/algorithms/-/blob/master/sortAlgorithms/heapsort/heapsort.rb

    ソース

    http://rosettacode.org/wiki/Sorting_algorithms/Heapsort
    https://www.youtube.com/watch?v=LbB357_RwlY

    https://habr.com/ru/company/ otus/blog/460087/

    https://ru.wikipedia.org/wiki/Pyramid_sort

    https://neerc.ifmo.ru/wiki /index.php?title=ヒープソート

    https://wiki5.ru/wiki/Heapsort

    https://wiki.c2.com/?HeapSort

    https://ru.wikipedia.org/wiki/Tree (データ構造)

    https://ru.wikipedia.org/wiki/Heap (データ構造)

    https://www.youtube.com/watch?v=2DmK_H7IdTo

    https://www.youtube.com/watch?v=kU4KBD4NFtw

    https://www.youtube.com/watch?v=DU1uG5310x0

    https://www.youtube.com/watch?v =BzQGPA_v-vc

    https://www.geeksforgeeks.org/バイナリヒープの配列表現/

    https://habr.com/ru/post/112222/

    https://www.cs.usfca. edu/~galles/visualization/BST.html

    https://www.youtube.com/watch?v=EQzqHWtsKq4

    https://medium.com/@dimko1/%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC% D1 %8B-%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8-heapsort-796ba965018b

    https://ru.wikibrief.org/wiki/Heapsort

    https://www.youtube.com/watch?v=GUUpmrTnNbw

    クイックソート

    クイックソートは分割統治型の並べ替えアルゴリズムです。再帰的に、部分ごとに数値の配列を解析し、選択した参照要素から小さい順に大きい順に数値を配置し、参照要素自体をそれらの間のカットオフに挿入します。何度か再帰的に繰り返すと、ソートされたリストが完成します。時間計算量 O(n2)。

    スキーム:

    <オル>

  • まず、外側から要素のリスト、つまり並べ替え境界を取得します。最初のステップでは、並べ替えの境界は最初から最後までになります。
  • 開始境界と終了境界が交差していないことを確認し、交差している場合は終了します。
  • リストから要素を選択し、それをピボットと呼びます
  • 邪魔にならないように、最後のインデックスまでに右に移動してください
  • ゼロに等しい *小さい数値* のカウンターを作成します
  • リストを左から右に、参照要素が配置されている最後のインデックスまでループします
  • 各要素を参照要素と比較します
  • それが参照値よりも小さい場合は、より小さい数値のカウンターのインデックスに従ってそれを交換します。より小さい数値のカウンタをインクリメントします。
  • ループがサポート要素に到達すると、停止し、より小さい数値のカウンターに従ってサポート要素を要素と交換します。
  • リストの左側の小さい部分と、リストの右側の大きい部分に対してアルゴリズムを別々に実行します。
  • その結果、ポイント 2 のチェックインにより、すべての再帰的反復が停止し始める
  • ソートされたリストを取得する
  • クイックソートは、モスクワ州立大学の科学者チャールズ アンソニー リチャード ホアによって発明されました。彼はロシア語を学び、コルモゴロフ学校でコンピューター翻訳と確率論を学びました。 1960 年、政治危機のため、彼はソ連を去りました。

    Rust での実装例:

    
    use rand::Rng;
    
    fn swap(numbers: &mut [i64], from: usize, to: usize) {
        let temp = numbers[from];
        numbers[from] = numbers[to];
        numbers[to] = temp;
    }
    
    fn quicksort(numbers: &mut [i64], left: usize, right: usize) {
        if left >= right {
            return
        }
        let length = right - left;
        if length <= 1 {
            return
        }
        let pivot_index = left + (length / 2);
        let pivot = numbers[pivot_index];
    
        let last_index = right - 1;
        swap(numbers, pivot_index, last_index);
    
        let mut less_insert_index = left;
    
        for i in left..last_index {
            if numbers[i] < pivot {
                swap(numbers, i, less_insert_index);
                less_insert_index += 1;
            }
        }
        swap(numbers, last_index, less_insert_index);
        quicksort(numbers, left, less_insert_index);
        quicksort(numbers, less_insert_index + 1, right);
    }
    
    fn main() {
        let mut numbers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let mut reference_numbers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    
        let mut rng = rand::thread_rng();
        for i in 0..numbers.len() {
            numbers[i] = rng.gen_range(-10..10);
            reference_numbers[i] = numbers[i];
        }
    
        reference_numbers.sort();
    
      println!("Numbers           {:?}", numbers);
      let length = numbers.len();
      quicksort(&mut numbers, 0, length);
      println!("Numbers           {:?}", numbers);
      println!("Reference numbers {:?}", reference_numbers);
    
      if numbers != reference_numbers {
        println!("Validation failed");
        std::process::exit(1);
      }
      else {
        println!("Validation success!");
        std::process::exit(0);
      }
    }
    

    何も明確でない場合は、サンディエゴ大学の Rob Edwards によるビデオを見ることをお勧めします https://www.youtube.com/watch?v=ZHVk2blR45Q アルゴリズムの本質と実装をステップごとに最も簡単に示しています。

    リンク

    https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/quickSort

    ソース

    https://www.youtube.com/watch?v =4s-aG6yGGLU
    https://www.youtube.com/watch?v=ywWBy6J5gz8
    https://www.youtube.com/watch?v=Hoixgm4-P4M
    https://ru.wikipedia.org/wiki/Быстрая_сортировка
    https://www.youtube.com/watch?v=Hoixgm4-P4M
    https://www.youtube.com/watch?v=XE4VP_8Y0BU
    https://www.youtube.com/watch?v=MZaf_9IZCrc
    https://www.youtube.com/watch?v=ZHVk2blR45Q
    http://rosettacode.org/wiki/Sorting_algorithms/Quicksort
    https://www.youtube.com/watch?v=4s-aG6yGGLU
    https://www.youtube.com/watch?v=dQw4w9WgXcQ
    https://www.youtube.com/watch?v=maibrCbZWKw
    https://www.geeksforgeeks.org/quick-sort/
    https://www.youtube.com/watch?v=uXBnyYuwPe8

    バイナリ挿入ソート

    二分挿入ソートは、二分検索を使用して挿入位置を決定する挿入ソートの変形です。アルゴリズムの時間計算量は O(n2) です

    アルゴリズムは次のように機能します:

    <オル>

  • ループは 0 からリストの最後まで始まります
  • ループ内で、並べ替えのために数値が選択され、その数値は別の変数に保存されます
  • 二分検索では、左側の数値に対してこの数値を挿入するためのインデックスが検索されます
  • インデックスが見つかると、挿入インデックスから開始して、左側の数字が 1 つ右にシフトされます。この過程で、並べ替える必要がある数値は消去されます。
  • 以前に保存した番号が挿入インデックスに挿入されます
  • ループの最後で、リスト全体が並べ替えられます
  • バイナリ検索中に、数値が見つからず、インデックスが返されない可能性があります。二分検索の特殊性により、検索された数値に最も近い数値が検索され、インデックスを返すには、そのインデックスを求めた数値と比較する必要があります。求めた数値が小さい場合、求めた数値は次の位置にある必要があります。インデックスが左側にあり、それ以上の場合は右側にあります。

    Go コード:

    
    import (
    	"fmt"
    	"math/rand"
    	"time"
    )
    
    const numbersCount = 20
    const maximalNumber = 100
    
    func binarySearch(numbers []int, item int, low int, high int) int {
    	for high > low {
    		center := (low + high) / 2
    		if numbers[center] < item { low = center + 1 } else if numbers[center] > item {
    			high = center - 1
    		} else {
    			return center
    		}
    	}
    
    	if numbers[low] < item {
    		return low + 1
    	} else {
    		return low
    	}
    }
    
    func main() {
    	rand.Seed(time.Now().Unix())
    	var numbers [numbersCount]int
    	for i := 0; i < numbersCount; i++ {
    		numbers[i] = rand.Intn(maximalNumber)
    	}
    	fmt.Println(numbers)
    
    	for i := 1; i < len(numbers); i++ { searchAreaLastIndex := i - 1 insertNumber := numbers[i] insertIndex := binarySearch(numbers[:], insertNumber, 0, searchAreaLastIndex) for x := searchAreaLastIndex; x >= insertIndex; x-- {
    			numbers[x+1] = numbers[x]
    		}
    		numbers[insertIndex] = insertNumber
    	}
    	fmt.Println(numbers)
    }
    

    リンク

    https://gitlab.com/demensdeum/algorithms/-/blob/master/sortAlgorithms/binaryInsertionSort/binaryInsertionSort.go

    ソース

    https://www.geeksforgeeks.org/binary-insertion-並べ替え/
    https://www.youtube.com/watch?v=-OVB5pOZJug

    シェルソート

    シェル ソート – 数値の配列を事前に組み合わせた挿入ソートの変形です。

    挿入ソートがどのように機能するかを覚えておく必要があります。

    1.ループは0からループの終わりまで開始されるため、配列は2つの部分に分割されます
    2. 左側の部分では、2 番目のループが開始され、要素を右から左に比較します。左側の小さい要素が見つかるまで、右側の小さい要素が削除されます。
    3. 両方のループの最後に、ソートされたリストが得られます。

    昔々、コンピューター科学者のドナルド シェルは、挿入ソート アルゴリズムを改善する方法を考えていました。彼はまた、最初に配列を 2 サイクルで処理するが、一定の距離を置き、通常の挿入ソート アルゴリズムに変わるまで「コーム」を徐々に減らしていくというアイデアも思いつきました。すべては非常に単純で、落とし穴はありません。上記の 2 つのサイクルに別のサイクルを追加し、「コーム」のサイズを徐々に小さくします。必要なのは、比較するときに配列を超えないよう距離を確認することだけです。

    本当に興味深いトピックは、最初のループの各反復で比較長を変更するためのシーケンスを選択することです。アルゴリズムのパフォーマンスがアルゴリズムに依存するという理由から、これは興味深いものです。

    既知のオプションと時間計算量の表は、https: //en .wikipedia.org/wiki/Shellsort#Gap_sequences

    理想的な距離の計算にはさまざまな人々が関与しており、このトピックは彼らにとって非常に興味深いものだったようです。 Ruby を実行して、最速の sort() アルゴリズムを呼び出すことはできないでしょうか?

    一般に、これらの奇妙な人々は、シェル アルゴリズムの「櫛」の距離/ギャップの計算をテーマに論文を書きました。私は彼らの研究結果を単純に使用し、Hibbard、Knuth-Pratt、Chiura、Sedgwick の 5 種類のシーケンスをチェックしました。

    import time
    import random
    from functools import reduce
    import math
    
    DEMO_MODE = False
    
    if input("Demo Mode Y/N? ").upper() == "Y":
        DEMO_MODE = True
    
    class Colors:
        BLUE = '\033[94m'
        RED = '\033[31m'
        END = '\033[0m'
    
    def swap(list, lhs, rhs):
        list[lhs], list[rhs] = list[rhs], list[lhs]
        return list
    
    def colorPrintoutStep(numbers: List[int], lhs: int, rhs: int):
        for index, number in enumerate(numbers):
            if index == lhs:
                print(f"{Colors.BLUE}", end = "")
            elif index == rhs:
                print(f"{Colors.RED}", end = "")
            print(f"{number},", end = "")
            if index == lhs or index == rhs:
                print(f"{Colors.END}", end = "")
            if index == lhs or index == rhs:
                print(f"{Colors.END}", end = "")
        print("\n")
        input(">")
    
    def ShellSortLoop(numbers: List[int], distanceSequence: List[int]):
        distanceSequenceIterator = reversed(distanceSequence)
        while distance:= next(distanceSequenceIterator, None):
            for sortArea in range(0, len(numbers)):
                for rhs in reversed(range(distance, sortArea + 1)):
                    lhs = rhs - distance
                    if DEMO_MODE:
                        print(f"Distance: {distance}")
                        colorPrintoutStep(numbers, lhs, rhs)
                    if numbers[lhs] > numbers[rhs]:
                        swap(numbers, lhs, rhs)
                    else:
                        break
    
    def ShellSort(numbers: List[int]):
        global ShellSequence
        ShellSortLoop(numbers, ShellSequence)
    
    def HibbardSort(numbers: List[int]):
        global HibbardSequence
        ShellSortLoop(numbers, HibbardSequence)
    
    def ShellPlusKnuttPrattSort(numbers: List[int]):
        global KnuttPrattSequence
        ShellSortLoop(numbers, KnuttPrattSequence)
    
    def ShellPlusCiuraSort(numbers: List[int]):
        global CiuraSequence
        ShellSortLoop(numbers, CiuraSequence)
    
    def ShellPlusSedgewickSort(numbers: List[int]):
        global SedgewickSequence
        ShellSortLoop(numbers, SedgewickSequence)
    
    def insertionSort(numbers: List[int]):
        global insertionSortDistanceSequence
        ShellSortLoop(numbers, insertionSortDistanceSequence)
    
    def defaultSort(numbers: List[int]):
        numbers.sort()
    
    def measureExecution(inputNumbers: List[int], algorithmName: str, algorithm):
        if DEMO_MODE:
            print(f"{algorithmName} started")
        numbers = inputNumbers.copy()
        startTime = time.perf_counter()
        algorithm(numbers)
        endTime = time.perf_counter()
        print(f"{algorithmName} performance: {endTime - startTime}")
    
    def sortedNumbersAsString(inputNumbers: List[int], algorithm) -> str:
        numbers = inputNumbers.copy()
        algorithm(numbers)
        return str(numbers)
    
    if DEMO_MODE:
        maximalNumber = 10
        numbersCount = 10
    else:
        maximalNumber = 10
        numbersCount = random.randint(10000, 20000)
    
    randomNumbers = [random.randrange(1, maximalNumber) for i in range(numbersCount)]
    
    ShellSequenceGenerator = lambda n: reduce(lambda x, _: x + [int(x[-1]/2)], range(int(math.log(numbersCount, 2))), [int(numbersCount / 2)])
    ShellSequence = ShellSequenceGenerator(randomNumbers)
    ShellSequence.reverse()
    ShellSequence.pop()
    
    HibbardSequence = [
        0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095,
        8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575,
        2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727,
        268435455, 536870911, 1073741823, 2147483647, 4294967295, 8589934591
    ]
    
    KnuttPrattSequence = [
        1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 
        797161, 2391484, 7174453, 21523360, 64570081, 193710244, 581130733, 
        1743392200, 5230176601, 15690529804, 47071589413
    ]
    
    CiuraSequence = [
                1, 4, 10, 23, 57, 132, 301, 701, 1750, 4376, 
                10941, 27353, 68383, 170958, 427396, 1068491, 
                2671228, 6678071, 16695178, 41737946, 104344866, 
                260862166, 652155416, 1630388541
    ]
    
    SedgewickSequence = [
                1, 5, 19, 41, 109, 209, 505, 929, 2161, 3905,
                8929, 16001, 36289, 64769, 146305, 260609, 587521, 
                1045505, 2354689, 4188161, 9427969, 16764929, 37730305, 
                67084289, 150958081, 268386305, 603906049, 1073643521, 
                2415771649, 4294770689, 9663381505, 17179475969
    ]
    
    insertionSortDistanceSequence = [1]
    
    algorithms = {
        "Default Python Sort": defaultSort,
        "Shell Sort": ShellSort,
        "Shell + Hibbard" : HibbardSort,
        "Shell + Prat, Knutt": ShellPlusKnuttPrattSort,
        "Shell + Ciura Sort": ShellPlusCiuraSort,
        "Shell + Sedgewick Sort": ShellPlusSedgewickSort,
        "Insertion Sort": insertionSort
    }
    
    for name, algorithm in algorithms.items():
        measureExecution(randomNumbers, name, algorithm)
    
    reference = sortedNumbersAsString(randomNumbers, defaultSort)
    
    for name, algorithm in algorithms.items():
        if sortedNumbersAsString(randomNumbers, algorithm) != reference:
            print("Sorting validation failed")
            exit(1)
    
    print("Sorting validation success")
    exit(0)
    

    私の実装では、ランダムな数値セットの場合、最も速いギャップはセジウィックとヒバードです。

    マイピー

    Python 3 – の静的型付けアナライザーについても触れておきたいと思います。マイピー。動的型付けを使用する言語に固有の問題に対処するのに役立ちます。つまり、不必要な場所に何かが貼り付けられる可能性を排除します。

    経験豊富なプログラマーが言うように、「専門家のチームがいる場合、静的型付けは必要ありません」。いつか私たち全員が専門家になり、完全に統一してマシンを理解しながらコードを書くようになりますが、今のところは同様のユーティリティを使用できます。静的型付け言語。

    リンク

    https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/shellSort
    http://mypy-lang.org/

    ソース

    https://dl.acm.org/doi/10.1145/368370.368387
    https://en.wikipedia.org/wiki/Shellsort
    http://rosettacode.org/wiki/Sorting_algorithms/Shell_sort
    https://ru.wikipedia.org/wiki/Сортировка_Шелла
    https://neerc.ifmo.ru/wiki/index.php?title=Сортировка_Шелла
    https://twitter.com/gvanrossum/status/700741601966985216

    二重選択ソート

    Double Selection Sort – 選択ソートのサブタイプで、速度が 2 倍になるようです。バニラのアルゴリズムは、数値のリストを 2 回ループし、最小の数値を見つけて、上のレベルのループが指す現在の数値と位置を交換します。二重選択ソートでは、最小値と最大値を検索し、– より上のレベルでループが指す 2 桁を置き換えます。左右に 2 つの数字。この乱交全体は、置換される数字のカーソルがリストの中央に見つかると終了します。その結果、ソートされた数字が視覚的中心の左右に取得されます。
    アルゴリズムの時間計算量は、選択ソートと同様です。 O(n2) ですが、おそらく 30 の加速度があると思われます%。

    境界線の状態

    この段階ですでに、衝突の瞬間を想像することができます。たとえば、左カーソルの番号 (最小値) がリスト内の最大値を指しているとき、最小値が再配置され、再配置が行われます。最大数がすぐに壊れてしまいます。したがって、アルゴリズムのすべての実装には、そのようなケースのチェックとインデックスの正しいものへの置き換えが含まれます。私の実装では、1 回のチェックで十分でした。

      maximalNumberIndex = minimalNumberIndex;
    }

    Реализация на Cito

    Cito – язык либ, язык транслятор. На нем можно писать для C, C++, C#, Java, JavaScript, Python, Swift, TypeScript, OpenCL C, при этом совершенно ничего не зная про эти языки. Исходный код на языке Cito транслируется в исходный код на поддерживаемых языках, далее можно использовать как библиотеку, либо напрямую, исправив сгенеренный код руками. Эдакий Write once – translate to anything.
    Double Selection Sort на cito:

    {
        public static int[] sort(int[]# numbers, int length)
        {
            int[]# sortedNumbers = new int[length];
            for (int i = 0; i < length; i++) {
                sortedNumbers[i] = numbers[i];
            }
            for (int leftCursor = 0; leftCursor < length / 2; leftCursor++) {
                int minimalNumberIndex = leftCursor;
                int minimalNumber = sortedNumbers[leftCursor];
    
                int rightCursor = length - (leftCursor + 1);
                int maximalNumberIndex = rightCursor;
                int maximalNumber = sortedNumbers[maximalNumberIndex];
    
                for (int cursor = leftCursor; cursor <= rightCursor; cursor++) { int cursorNumber = sortedNumbers[cursor]; if (minimalNumber > cursorNumber) {
                        minimalNumber = cursorNumber;
                        minimalNumberIndex = cursor;
                    }
                    if (maximalNumber < cursorNumber) {
                        maximalNumber = cursorNumber;
                        maximalNumberIndex = cursor;
                    }
                }
    
                if (leftCursor == maximalNumberIndex) {
                    maximalNumberIndex = minimalNumberIndex;
                }
    
                int fromNumber = sortedNumbers[leftCursor];
                int toNumber = sortedNumbers[minimalNumberIndex];
                sortedNumbers[minimalNumberIndex] = fromNumber;
                sortedNumbers[leftCursor] = toNumber;
    
                fromNumber = sortedNumbers[rightCursor];
                toNumber = sortedNumbers[maximalNumberIndex];
                sortedNumbers[maximalNumberIndex] = fromNumber;
                sortedNumbers[rightCursor] = toNumber;
            }
            return sortedNumbers;
        }
    } 
    

    リンク

    https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/doubleSelectionSort
    https://github.com/pfusik/cito

    ソース

    https://www.researchgate.net/publication/330084245_改良_Double_Selection_Sort_using_Algorithm
    http://algolab.valemak.com/selection-double
    https://www.geeksforgeeks.org/sorting-algorithm-slightly-improves-selection-sort/

    カクテルシェーカーの並べ替え

    カクテル シェーカー ソート –双方向バブルソーティングの一種であるシェーカーソーティング。
    アルゴリズムは次のように機能します。

    <オル>

  • ループ内での最初の検索方向が選択されます (通常は左から右)
  • ループの次に、数値がペアでチェックされます
  • 次の要素の方が大きい場合、それらは交換されます
  • 終了すると、検索プロセスが方向を逆にして再び開始されます
  • 検索は順列がなくなるまで繰り返されます
  • アルゴリズムの時間計算量はバブル – に似ています。 O(n2)

    PHP での実装例:

    <?php
    
    function cocktailShakeSort($numbers)
    {
        echo implode(",", $numbers),"\n";
        $direction = false;
        $sorted = false;
        do {
            $direction = !$direction;        
            $firstIndex = $direction == true ? 0 : count($numbers) - 1;
            $lastIndex = $direction == true ? count($numbers) - 1 : 0;
            
            $sorted = true;
            for (
                $i = $firstIndex;
                $direction == true ? $i < $lastIndex : $i > $lastIndex;
                $direction == true ? $i++ : $i--
            ) {
                $lhsIndex = $direction ? $i : $i - 1;
                $rhsIndex = $direction ? $i + 1 : $i;
    
                $lhs = $numbers[$lhsIndex];
                $rhs = $numbers[$rhsIndex];
    
                if ($lhs > $rhs) {
                    $numbers[$lhsIndex] = $rhs;
                    $numbers[$rhsIndex] = $lhs;
                    $sorted = false;
                }
            }
        } while ($sorted == false);
    
        echo implode(",", $numbers);
    }
    
    $numbers = [2, 1, 4, 3, 69, 35, 55, 7, 7, 2, 6, 203, 9];
    cocktailShakeSort($numbers);
    
    ?>

    Ссылки

    https://gitlab.com/demensdeum/algorithms/-/blob/master/sortAlgorithms/cocktailShakerSort/cocktailShakerSort.php

    Источники

    https://www.youtube.com/watch?v=njClLBoEbfI
    https://www.geeksforgeeks.org/cocktail-sort/
    https://rosettacode.org/wiki/Sorting_algorithms/Cocktail_sort

    スリープソート

    睡眠並べ替え – sleep sort は、決定論的な奇妙な並べ替えアルゴリズムのもう 1 つの代表です。

    次のように動作します:

    <オル>

  • 要素のリストをループします
  • ループごとに別のスレッドが起動される
  • スレッドは一定期間スリープします –要素の値とスリープ後に出力される値
  • ループの最後で、スレッドの最長スリープが完了するまで待機し、並べ替えられたリストを表示します
  • C での睡眠ソート アルゴリズムのサンプル コード:

    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    
    typedef struct {
        int number;
    } ThreadPayload;
    
    void *sortNumber(void *args) {
        ThreadPayload *payload = (ThreadPayload*) args;
        const int number = payload->number;
        free(payload);
        usleep(number * 1000);
        printf("%d ", number);
        return NULL;
    }
    
    int main(int argc, char *argv[]) {
        const int numbers[] = {2, 42, 1, 87, 7, 9, 5, 35};
        const int length = sizeof(numbers) / sizeof(int);
    
        int maximal = 0;
        pthread_t maximalThreadID;
    
        printf("Sorting: ");
        for (int i = 0; i < length; i++) { pthread_t threadID; int number = numbers[i]; printf("%d ", number); ThreadPayload *payload = malloc(sizeof(ThreadPayload)); payload->number = number;
            pthread_create(&threadID, NULL, sortNumber, (void *) payload);
            if (maximal < number) {
                maximal = number;
                maximalThreadID = threadID;
            }
        }
        printf("\n");
        printf("Sorted: ");
        pthread_join(maximalThreadID, NULL);
        printf("\n");
        return 0;
    }
    

    この実装では、マイクロ秒で usleep 関数を使用し、値に 1000 を乗算しました。ミリ秒単位
    で。アルゴリズムの時間計算量 – O(とても長い)

    リンク

    https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/sleepSort

    ソース

    https://codoholicconfessions.wordpress。 com/2017/05/21/strangest-sorting-algorithms/
    https://twitter.com/javascriptdaily/status/856267407106682880?lang=en
    https://stackoverflow.com/questions/6474318/what-is-the-time-complexity-of-the-sleep-sort

    スターリンソート

    スターリン ソート – sort through は、データ損失を伴う並べ替えアルゴリズムの 1 つです。
    このアルゴリズムは非常に生産的効率的で、時間計算量は O(n) です。

    次のように動作します:

    <オル>

  • 配列をループし、現在の要素と次の要素を比較します
  • 次の要素が現在の要素より小さい場合は、それを削除します
  • 結果として、O(n) でソートされた配列が得られます
  • アルゴリズムの出力の例:

    Gulag: [1, 3, 2, 4, 6, 42, 4, 8, 5, 0, 35, 10]
    Element 2 sent to Gulag
    Element 4 sent to Gulag
    Element 8 sent to Gulag
    Element 5 sent to Gulag
    Element 0 sent to Gulag
    Element 35 sent to Gulag
    Element 10 sent to Gulag
    Numbers: [1, 3, 4, 6, 42]
    Gulag: [2, 4, 8, 5, 0, 35, 10]
    

    Python 3 コード:

    gulag = []
    
    print(f"Numbers: {numbers}")
    print(f"Gulag: {numbers}")
    
    i = 0
    maximal = numbers[0]
    
    while i < len(numbers):
        element = numbers[i]
        if maximal > element:
            print(f"Element {element} sent to Gulag")
            gulag.append(element)
            del numbers[i]
        else:
            maximal = element        
            i += 1
    
    print(f"Numbers: {numbers}")
    print(f"Gulag: {gulag}")
    

    欠点としてはデータ損失が挙げられますが、O(n) で理想的なソート済みリストを実現するためには、他にどのような方法があるでしょうか?

    リンク

    https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/stalinSort

    ソース

    https://github.com/gustavo-depaula/stalin-sort
    https://www.youtube.com/shorts/juRL-Xn-E00
    https://www.youtube.com/watch?v=L78i2YcyYfk

    選択範囲の並べ替え

    選択並べ替え –選択ソートアルゴリズム。何を選ぶの?でも最低数!!!
    アルゴリズムの時間計算量 – O(n2)

    アルゴリズムは次のように機能します。

    <オル>

  • 配列を左から右にループ処理し、現在の開始インデックスとインデックスの番号を覚えておきます。番号 A とします
  • ループ内で、別のループを実行して左から右に移動し、A より小さいものを探します
  • 小さい方を見つけたらインデックスを覚えます。今度は小さい方が数字 A になります
  • 内側のループが終了したら、開始インデックスの数値と数値 A を交換します
  • 上のループを完全に通過すると、ソートされた配列が得られます
  • アルゴリズムの実行例:

    (29, 49, 66, 35, 7, 12, 80)
    29 > 7
    (7, 49, 66, 35, 29, 12, 80)
    Round 1 ENDED
    Round 2
    (7, 49, 66, 35, 29, 12, 80)
    49 > 35
    35 > 29
    29 > 12
    (7, 12, 66, 35, 29, 49, 80)
    Round 2 ENDED
    Round 3
    (7, 12, 66, 35, 29, 49, 80)
    66 > 35
    35 > 29
    (7, 12, 29, 35, 66, 49, 80)
    Round 3 ENDED
    Round 4
    (7, 12, 29, 35, 66, 49, 80)
    (7, 12, 29, 35, 66, 49, 80)
    Round 4 ENDED
    Round 5
    (7, 12, 29, 35, 66, 49, 80)
    66 > 49
    (7, 12, 29, 35, 49, 66, 80)
    Round 5 ENDED
    Round 6
    (7, 12, 29, 35, 49, 66, 80)
    (7, 12, 29, 35, 49, 66, 80)
    Round 6 ENDED
    Sorted: (7, 12, 29, 35, 49, 66, 80)
    

    Rosetta コードで Objective-C 実装が見つかりませんでした。 、私は自分でこう書きました。

    #include <Foundation/Foundation.h>
    
    @implementation SelectionSort
    - (void)performSort:(NSMutableArray *)numbers
    {
       NSLog(@"%@", numbers);   
       for (int startIndex = 0; startIndex < numbers.count-1; startIndex++) {
          int minimalNumberIndex = startIndex;
          for (int i = startIndex + 1; i < numbers.count; i++) {
             id lhs = [numbers objectAtIndex: minimalNumberIndex];
             id rhs = [numbers objectAtIndex: i];
             if ([lhs isGreaterThan: rhs]) {
                minimalNumberIndex = i;
             }
          }
          id temporary = [numbers objectAtIndex: minimalNumberIndex];
          [numbers setObject: [numbers objectAtIndex: startIndex] 
                   atIndexedSubscript: minimalNumberIndex];
          [numbers setObject: temporary
                   atIndexedSubscript: startIndex];
       }
       NSLog(@"%@", numbers);
    }
    
    @end 

    Собрать и запустить можно либо на MacOS/Xcode, либо на любой операционной системе поддерживающей GNUstep, например у меня собирается Clang на Arch Linux.
    Скрипт сборки:

            main.m \
            -lobjc \
            `gnustep-config --objc-flags` \
            `gnustep-config --objc-libs` \
            -I /usr/include/GNUstepBase \
            -I /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/include/ \
            -lgnustep-base \
            -o SelectionSort \

    Links

    https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/selectionSort

    Sources

    https://rosettacode.org/wiki/Sorting_algorithms/Selection_sort
    https://ru.wikipedia.org/wiki/Сортировка_выбором
    https://en.wikipedia.org/wiki/Selection_sort
    https://www.youtube.com/watch?v=LJ7GYbX7qpM

    カウンティングソート

    カウントソート–カウントソートアルゴリズム。に関しては?はい!そのとおりです!

    アルゴリズムには少なくとも 2 つの配列が含まれます。最初の配列は –ソートする整数のリスト、2 番目 –サイズ = (最大数 – 最小数) + 1 の配列。最初はゼロのみを含みます。次に、最初の配列から数値が並べ替えられ、その数値要素を使用して 2 番目の配列のインデックスが取得され、1 ずつ増分されます。リスト全体を調べた後、最初の配列からの数値の繰り返し数を含む、完全に満たされた 2 番目の配列が得られます。 アルゴリズムには重大なオーバーヘッドがあります – 2 番目の配列には、最初のリストにない数値のゼロも含まれます。メモリによるオーバーヘッド

    2 番目の配列を受け取った後、それを反復処理し、インデックスでソートされた数値を書き込み、カウンターを 0 にデクリメントします。最初は、ゼロ カウンタは無視されます。

    カウントソートアルゴリズムの最適化されていない操作の例:

    <オル>

  • 入力配列 1,9,1,4,6,4,4
  • カウントする配列は 0,1,2,3,4,5,6,7,8,9 になります (最小値は 0、最大値は 9)
  • 合計カウンタが 0,2,0,0,3,0,1,0,0,1 の場合
  • ソートされた配列の合計 1,1,4,4,4,6,9
  • Python 3 のアルゴリズム コード:

    
    numbers = [42, 89, 69, 777, 22, 35, 42, 69, 42, 90, 777]
    
    minimal = min(numbers)
    maximal = max(numbers)
    countListRange = maximal - minimal
    countListRange += 1
    countList = [0] * countListRange
    
    print(numbers)
    print(f"Minimal number: {minimal}")
    print(f"Maximal number: {maximal}")
    print(f"Count list size: {countListRange}")
    
    for number in numbers:
        index = number - minimal
        countList[index] += 1
    
    replacingIndex = 0
    for index, count in enumerate(countList):
        for i in range(count):
            outputNumber = minimal + index
            numbers[replacingIndex] = outputNumber
            replacingIndex += 1
    
    print(numbers)

    Из-за использования двух массивов, временная сложность алгоритма O(n + k)

    Ссылки

    https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/countingSort

    Источники

    https://www.youtube.com/watch?v=6dk_csyWif0
    https://www.youtube.com/watch?v=OKd534EWcdk
    https://en.wikipedia.org/wiki/Counting_sort
    https://rosettacode.org/wiki/Sorting_algorithms/Counting_sort
    https://pro-prof.com/forums/topic/%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC-%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8-%D0%BF%D0%BE%D0%B4%D1%81%D1%87%D0%B5%D1%82%D0%BE%D0%BC

    ボゴソート

    疑似ソートまたはスワンプ ソート。最も役に立たないソート アルゴリズムの 1 つ。

    次のように動作します。
    1. 入力は数値の配列です
    2. 数字の配列をランダムにシャッフル(シャッフル)する
    3. 配列がソートされているかどうかを確認します
    4. ソートされていない場合、配列は再度シャッフルされます
    5. 配列がランダムに並べ替えられるまで、このすべてのアクションが繰り返されます。

    ご覧のとおり、このアルゴリズムのパフォーマンスはひどいもので、賢い人は O(n * n!) さえも信じています。何年もの間、カオスの神の栄光のためにサイコロを投げることに行き詰まる可能性があります。配列は決してソートされません。それともソートされるかもしれません >

    実装

    TypeScript で実装するには、次の関数を実装する必要がありました。
    1. オブジェクトの配列をシャッフルする
    2. 配列の比較
    3. 0 から数値 (原文どおり!) までの範囲の乱数を生成します
    4. 進行状況を印刷します。並べ替えは延々と続くようです

    以下は TypeScript 実装コードです。

    const randomInteger = (maximal: number) => Math.floor(Math.random() * maximal);
    const isEqual = (lhs: any[], rhs: any[]) => lhs.every((val, index) => val === rhs[index]);
    const shuffle = (array: any[]) => {
        for (var i = 0; i < array.length; i++) { var destination = randomInteger(array.length-1); var temp = array[i]; array[i] = array[destination]; array[destination] = temp; } } let numbers: number[] = Array.from({length: 10}, ()=>randomInteger(10));
    const originalNumbers = [...numbers];
    const sortedNumbers = [...numbers].sort();
    
    let numberOfRuns = 1;
    
    do {
        if (numberOfRuns % 1000 == 0) {
            printoutProcess(originalNumbers, numbers, numberOfRuns);
        }
        shuffle(numbers);
        numberOfRuns++;
    } while (isEqual(numbers, sortedNumbers) == false)
    
    console.log(`Success!`);
    console.log(`Run number: ${numberOfRuns}`)
    console.log(`Original numbers: ${originalNumbers}`);
    console.log(`Current numbers: ${originalNumbers}`);
    console.log(`Sorted numbers: ${sortedNumbers}`);

    Для отладки можно использовать VSCode и плагин TypeScript Debugger от kakumei.

    Как долго

    Вывод работы алгоритма:

    src/bogosort.ts:1
    Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 8,7,0,2,4,7,2,5,9,5, try number: 145000
    src/bogosort.ts:2
    Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 7,5,2,4,9,8,0,5,2,7, try number: 146000
    src/bogosort.ts:2
    Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 0,2,7,4,9,5,7,5,8,2, try number: 147000
    src/bogosort.ts:2
    Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 5,9,7,8,5,4,2,7,0,2, try number: 148000
    src/bogosort.ts:2
    Success!
    src/bogosort.ts:24
    Run number: 148798
    src/bogosort.ts:25
    Original numbers: 5,4,8,7,5,0,2,9,7,2
    src/bogosort.ts:26
    Current numbers: 5,4,8,7,5,0,2,9,7,2
    src/bogosort.ts:27
    Sorted numbers: 0,2,2,4,5,5,7,7,8,9

    Для массива из 10 чисел Богосорт перемешивал исходный массив 148798 раз, многовато да?
    Алгоритм можно использовать как учебный, для понимания возможностей языка с которым предстоит работать на рынке. Лично я был удивлен узнав что в ванильных JS и TS до сих пор нет своего алгоритма перемешивания массивов, генерации целого числа в диапазоне, доступа к хэшам объектов для быстрого сравнения.

    Ссылки

    https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/bogosort
    https://www.typescriptlang.org/
    https://marketplace.visualstudio.com/items?itemName=kakumei.ts-debug

    Источники

    https://www.youtube.com/watch?v=r2N3scbd_jg
    https://en.wikipedia.org/wiki/Bogosort

    挿入ソート、マージソート

    挿入並べ替え

    挿入並べ替え –各要素はリスト内の前の要素と比較され、 大きい方の要素があればその要素と交換されます。それ以外の場合は内部比較ループが実行されます。止まります。要素は最初から最後までソートされるため、各要素はすでにソートされたリストと比較され、*おそらく* 全体の実行時間が短縮されます。アルゴリズムの時間計算量は O(n^2)、つまりバブルの種類と同じです。

    並べ替えを結合

    並べ替えを結合–リストは 1 つの要素のグループに分割され、その後、それらのグループがペアで「マージ」され、同時に比較されます。私の実装では、ペアをマージするときに、左側の要素が右側の要素と比較され、左側の要素がなくなった場合は、右側のすべての要素が結果のリストに追加されます。 list (グループ内のすべての要素が繰り返しソートされるため、追加の比較は不要です)< br />このアルゴリズムの作業は並列化するのが非常に簡単です。ペアを結合する段階は、ディスパッチャーでの反復の終了を待ってスレッドで実行できます。
    シングルスレッド実行のアルゴリズムの出力:

    ["John", "Alice", "Mike", "#1", "Артем", "20", "60", "60", "DoubleTrouble"]
    [["John"], ["Alice"], ["Mike"], ["#1"], ["Артем"], ["20"], ["60"], ["60"], ["DoubleTrouble"]]
    [["Alice", "John"], ["#1", "Mike"], ["20", "Артем"], ["60", "60"], ["DoubleTrouble"]]
    [["#1", "Alice", "John", "Mike"], ["20", "60", "60", "Артем"], ["DoubleTrouble"]]
    [["#1", "20", "60", "60", "Alice", "John", "Mike", "Артем"], ["DoubleTrouble"]]
    ["#1", "20", "60", "60", "Alice", "DoubleTrouble", "John", "Mike", "Артем"]
    
    

    マルチスレッド実行のアルゴリズムの出力:

    ["John", "Alice", "Mike", "#1", "Артем", "20", "60", "60", "DoubleTrouble"]
    [["John"], ["Alice"], ["Mike"], ["#1"], ["Артем"], ["20"], ["60"], ["60"], ["DoubleTrouble"]]
    [["20", "Артем"], ["Alice", "John"], ["60", "60"], ["#1", "Mike"], ["DoubleTrouble"]]
    [["#1", "60", "60", "Mike"], ["20", "Alice", "John", "Артем"], ["DoubleTrouble"]]
    [["DoubleTrouble"], ["#1", "20", "60", "60", "Alice", "John", "Mike", "Артем"]]
    ["#1", "20", "60", "60", "Alice", "DoubleTrouble", "John", "Mike", "Артем"]
    
    

    アルゴリズムの時間計算量は O(n*log(n)) で、O(n^2) よりわずかに優れています

    ソース

    https://en.wikipedia.org/wiki/Insertion_sort
    https://en.wikipedia.org/wiki/Merge_sort

    ソースコード

    https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/insertionSort
    https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/mergeSort

    Erlang のバブルソート

    バブル ソートは非常に退屈ですが、通信用の関数型言語で実装してみるとさらに面白くなります。アーラン。

    数値のリストがあるので、それを並べ替える必要があります。バブル ソート アルゴリズムは、リスト全体を調べて、数値をペアごとに反復して比較します。チェック中に次の処理が行われます。出力リストに小さい番号が追加されるか、現在のリスト内の番号が交換されます。右側の番号が小さい場合は、反復内の次の番号で検索が続行されます。この走査は、リストに置換がなくなるまで繰り返されます。

    実際には、アルゴリズムの時間の複雑さのため、使用する価値はありません – O(n^2);私は Erlang で命令型スタイルで実装しましたが、興味がある場合は、より良いオプションを探すことができます。

    -module(bubbleSort).
    -export([main/1]).
    
    startBubbleSort([CurrentHead|Tail]) ->
        compareHeads(CurrentHead, Tail, [], [CurrentHead|Tail]).
    
    compareHeads(CurrentHead, [NextHead|Tail], [], OriginalList) ->   
        if
            CurrentHead < NextHead ->
                compareHeads(NextHead, Tail, [CurrentHead], OriginalList);
            true ->
                compareHeads(CurrentHead, Tail, [NextHead], OriginalList)
        end;
        
    compareHeads(CurrentHead, [NextHead|Tail], OriginalOutputList, OriginalList) ->
        if
            CurrentHead < NextHead ->
                OutputList = OriginalOutputList ++ [CurrentHead],
                compareHeads(NextHead, Tail, OutputList, OriginalList);
            true ->
                OutputList = OriginalOutputList ++ [NextHead],
                compareHeads(CurrentHead, Tail, OutputList, OriginalList)
        end;
      
    compareHeads(CurrentHead, [], OriginalOutputList, OriginalList) ->
        OutputList = OriginalOutputList ++ [CurrentHead],
        if
            OriginalList == OutputList ->
                io:format("OutputList: ~w~n", [OutputList]);
            true ->
                startBubbleSort(OutputList)
        end.
      
    main(_) ->
        UnsortedList = [69,7,4,44,2,9,10,6,26,1],
        startBubbleSort(UnsortedList).
    
    

    インストールと起動

    Ubuntu では、Erlang のインストールは非常に簡単です。ターミナルに sudo apt install erlang と入力するだけです。この言語では、各ファイルは外部で使用できる関数のリストを含むモジュールである必要があります。輸出。この言語の興味深い特徴には、変数がなく定数のみであること、OOP の標準構文がないこと (OOP テクニックの使用を妨げるものではありません)、そしてもちろんアクター モデルに基づくロックなしの並列計算が含まれます。

    モジュールは、対話型 erl コンソールを使用してコマンドを次々に実行するか、あるいはもっと簡単に escript bubbleSort.erl を使用して実行できます。ケースが異なると、ファイルの外観も異なります。たとえば、escript の場合は、開始元となる main 関数を作成する必要があります。

    ソース

    https://www.erlang.org/
    https://habr.com/ru/post/197364/

    ソースコード

    https://gitlab.com/ demensdeum/algorithms/blob/master/bubbleSort/bubbleSort.erl