Python を使用してさまざまな並べ替えアルゴリズムを実装する

大家讲道理
リリース: 2016-11-07 17:01:15
オリジナル
1057 人が閲覧しました

一般的な集中並べ替えアルゴリズムの概要

マージ ソート

マージ ソートとも呼ばれるマージ ソートは、分割統治法の典型的な応用です。分割統治の考え方は、それぞれの問題を小さな問題に分解し、それぞれの小さな問題を解決してから、それらを統合することです。

具体的なマージソートは、順序付けされていない数値のセットを n/2 ずつ 1 つの要素だけを持つサブ項目に再帰的に分解することであり、1 つの要素はすでにソートされています。次に、これらの順序付けされたサブ要素をマージします。

マージのプロセスは、ソートされた 2 つのサブシーケンスを比較し、最初に 2 つのサブシーケンスの最小の要素を選択し、2 つの要素の最小のサブシーケンスを選択し、それをサブシーケンスから削除して最終結果セットに追加します

。サブシーケンスはマージされます。

コードは次のとおりです:

#!/usr/bin/python  
import sys  
   
def merge(nums, first, middle, last):  
    ''''' merge '''  
    # 切片边界,左闭右开并且是了0为开始  
    lnums = nums[first:middle+1]   
    rnums = nums[middle+1:last+1]  
    lnums.append(sys.maxint)  
    rnums.append(sys.maxint)  
    l = 0  
    r = 0  
    for i in range(first, last+1):  
        if lnums[l] < rnums[r]:  
            nums[i] = lnums[l]  
            l+=1  
        else:  
            nums[i] = rnums[r]  
            r+=1  
def merge_sort(nums, first, last):  
    &#39;&#39;&#39;&#39;&#39; merge sort 
    merge_sort函数中传递的是下标,不是元素个数 
    &#39;&#39;&#39;  
    if first < last:  
        middle = (first + last)/2  
        merge_sort(nums, first, middle)  
        merge_sort(nums, middle+1, last)  
        merge(nums, first, middle,last)  
   
if __name__ == &#39;__main__&#39;:  
    nums = [10,8,4,-1,2,6,7,3]  
    print &#39;nums is:&#39;, nums  
    merge_sort(nums, 0, 7)  
    print &#39;merge sort:&#39;, nums
ログイン後にコピー

安定した時間計算量 O(nlog n)

挿入ソート

コードは次のとおりです:

#!/usr/bin/python  
import sys  
   
def insert_sort(a):
ログイン後にコピー

''''' 挿入ソート

すでに順序付けられたデータ列。この整列したデータ列に数値を挿入する必要がありますが、挿入後もデータ列が順序どおりであることが必要です。最初は明らかに 1 つの要素が順番に配置されており、次に適切な位置に要素を挿入し、次に 3 番目の要素を挿入する、というように続きます

''''

   a_len = len(a)  
    if a_len = 0 and a[j] > key:  
            a[j+1] = a[j]  
            j-=1  
        a[j+1] = key  
    return a  
   
if __name__ == &#39;__main__&#39;:  
    nums = [10,8,4,-1,2,6,7,3]  
    print &#39;nums is:&#39;, nums  
    insert_sort(nums)  
    print &#39;insert sort:&#39;, nums
ログイン後にコピー

は安定しており、時間計算量は O( n^2)

Python で 2 つの要素の値を交換するには、次のように記述できます: a, b = b, a。実際、これは代入記号の左側と右側がタプルであるためです

(ここで強調しておく必要があるのは、Python ではタプル グループは実際には括弧ではなくカンマ「,」で区切られるということです。

選択ソート

選択ソートは、シンプルで直感的な並べ替えアルゴリズムです。仕組みは次のとおりです。まず、ソートされていないシーケンス内で最小の (大きい) 要素を見つけて、ソートされたシーケンスの先頭に格納します。次に、ソートされていない残りの要素から最小の (大きい) 要素を見つけて、それをソートされたシーケンスの最後に置きます。ソートされたシーケンス。すべての要素がソートされるまで続きます。

import sys  
def select_sort(a):
ログイン後にコピー

'''' 選択ソート

各パスで、ソートされるデータ要素から最小 (または最大) の要素が選択され、すべての要素が揃うまで

がソートされたシーケンスの最後に配置されます。ソートされるデータ要素が完成します。

選択ソートは不安定なソート方法です。

'' r
  a_len=len(a)  
    for i in range(a_len):#在0-n-1上依次选择相应大小的元素   
        min_index = i#记录最小元素的下标   
        for j in range(i+1, a_len):#查找最小值  
            if(a[j]<a[min_index]):  
                min_index=j  
        if min_index != i:#找到最小元素进行交换  
            a[i],a[min_index] = a[min_index],a[i]  
   
if __name__ == &#39;__main__&#39;:  
    A = [10, -3, 5, 7, 1, 3, 7]    
    print &#39;Before sort:&#39;,A    
    select_sort(A)    
    print &#39;After sort:&#39;,A
ログイン後にコピー

は不安定で、時間計算量 O (n^2)

ヒル ソート

ヒル ソートは、減少増分ソート アルゴリズムとしても知られており、ヒルのソートは非安定ソート アルゴリズムです。この方法は、DL であるため、増分ソートの削減とも呼ばれます。シェルは 1959 年に提案されたことにちなんで名付けられました。

まず最初の増分として n より小さい整数 d1 をとり、ファイル内のすべてのレコードを d1 グループに分割します。距離が d1 の倍数であるすべてのレコードは、同じグループに配置されます。最初に各グループ内で並べ替えます

次に、2 番目の増分 d2

def shell_sort(a):  
    &#39;&#39;&#39;&#39;&#39; shell排序  
    &#39;&#39;&#39;  
    a_len=len(a)  
    gap=a_len/2#增量  
    while gap>0:  
        for i in range(a_len):#对同一个组进行选择排序  
            m=i  
            j=i+1  
            while j<a_len:  
                if a[j]<a[m]:  
                    m=j  
                j+=gap#j增加gap  
            if m!=i:  
                a[m],a[i]=a[i],a[m]  
        gap/=2  
   
if __name__ == &#39;__main__&#39;:  
    A = [10, -3, 5, 7, 1, 3, 7]    
    print &#39;Before sort:&#39;,A    
    shell_sort(A)    
    print &#39;After sort:&#39;,A
ログイン後にコピー

不安定、時間計算量平均時間 O(nlogn) 最悪時間 O(n^s)1

ヒープソート (ヒープソート)

「ヒープ」の定義:開始インデックスが 0 の「ヒープ」:

ノード i の右の子ノードは位置 2 * i + 24) ノード i の親ノードは位置 Floor( (i - 1) / 2) にあることに注意してください。フロアは「丸め」操作を意味します

ヒープの特性:

各ノードのキー値は常に​​その親ノードより大きい (または小さい) 必要があります

「最大ヒープ」:

「ヒープ」のルート ノードキーを保存します 最大値を持つノード。つまり、「ヒープ」内の各ノードのキー値は、常にその子ノードよりも大きくなります。

上に移動、下に移動:

ノードのキー値が親ノードより大きい場合、「上に移動」操作を実行する必要があります。つまり、ノードを親ノードの位置に移動します。 ,

その親ノードをその位置に置いて、ノードの判断を続け、ノードが親ノードより大きくなくなるまで「上への移動」を停止しません。

ここで、「下に移動」操作について詳しく学びましょう。ノードのキー値をより小さい値に変更する場合は、「下に移動」する必要があります。

方法:

最初に最大のヒープ (時間計算量 O(n)) を構築し、その後毎回、ルート ノードを最後の位置のノードと交換するだけで済み、その後、最後の位置を除外し、交換後、ルート ノードのヒープが調整されます (時間計算量 O(lgn))。つまり、ルート ノードを「下に移動」できます。 ヒープソートの合計時間計算量は O(nlgn) です。

コードは次のとおりです:

#!/usr/bin env python  
   
# 数组编号从 0开始  
def left(i):  
    return 2*i +1  
def right(i):  
    return 2*i+2  
   
#保持最大堆性质 使以i为根的子树成为最大堆  
def max_heapify(A, i, heap_size):  
    if heap_size <= 0:  
        return   
    l = left(i)  
    r = right(i)  
    largest = i # 选出子节点中较大的节点  
    if l  A[largest]:  
        largest = l  
    if r  A[largest]:  
        largest = r  
    if i != largest :#说明当前节点不是最大的,下移  
        A[i], A[largest] = A[largest], A[i] #交换  
        max_heapify(A, largest, heap_size)#继续追踪下移的点  
    #print A  
# 建堆    
def bulid_max_heap(A):  
    heap_size = len(A)  
    if heap_size >1:  
        node = heap_size/2 -1  
        while node >= 0:  
           max_heapify(A, node, heap_size)  
           node -=1  
   
# 堆排序 下标从0开始  
def heap_sort(A):  
    bulid_max_heap(A)  
    heap_size = len(A)  
    i = heap_size - 1   
    while i > 0 :  
        A[0],A[i] = A[i], A[0] # 堆中的最大值存入数组适当的位置,并且进行交换  
        heap_size -=1 # heap 大小 递减 1  
        i -= 1 # 存放堆中最大值的下标递减 1  
        max_heapify(A, 0, heap_size)  
   
if __name__ == &#39;__main__&#39; :  
   
    A = [10, -3, 5, 7, 1, 3, 7]  
    print &#39;Before sort:&#39;,A  
    heap_sort(A)  
    print &#39;After sort:&#39;,A
ログイン後にコピー

不稳定,时间复杂度 O(nlog n)

快速排序

快速排序算法和合并排序算法一样,也是基于分治模式。对子数组A[p...r]快速排序的分治过程的三个步骤为:

分解:把数组A[p...r]分为A[p...q-1]与A[q+1...r]两部分,其中A[p...q-1]中的每个元素都小于等于A[q]而A[q+1...r]中的每个元素都大于等于A[q];

解决:通过递归调用快速排序,对子数组A[p...q-1]和A[q+1...r]进行排序;

合并:因为两个子数组是就地排序的,所以不需要额外的操作。

对于划分partition 每一轮迭代的开始,x=A[r], 对于任何数组下标k,有:

1) 如果p≤k≤i,则A[k]≤x。

2) 如果i+1≤k≤j-1,则A[k]>x。

3) 如果k=r,则A[k]=x。

代码如下:

#!/usr/bin/env python  
# 快速排序  
&#39;&#39;&#39;&#39;&#39; 
划分 使满足 以A[r]为基准对数组进行一个划分,比A[r]小的放在左边, 
   比A[r]大的放在右边 
快速排序的分治partition过程有两种方法, 
一种是上面所述的两个指针索引一前一后逐步向后扫描的方法, 
另一种方法是两个指针从首位向中间扫描的方法。 
&#39;&#39;&#39;  
#p,r 是数组A的下标  
def partition1(A, p ,r):  
    &#39;&#39;&#39;&#39;&#39; 
      方法一,两个指针索引一前一后逐步向后扫描的方法 
    &#39;&#39;&#39;  
    x = A[r]  
    i = p-1  
    j = p  
    while j < r:  
        if A[j] < x:  
            i +=1  
            A[i], A[j] = A[j], A[i]  
        j += 1  
    A[i+1], A[r] = A[r], A[i+1]  
    return i+1  
   
def partition2(A, p, r):  
    &#39;&#39;&#39;&#39;&#39; 
    两个指针从首尾向中间扫描的方法 
    &#39;&#39;&#39;  
    i = p  
    j = r  
    x = A[p]  
    while i = x and i < j:  
            j -=1  
        A[i] = A[j]  
        while A[i]<=x and i < j:  
            i +=1  
        A[j] = A[i]  
    A[i] = x  
    return i  
   
# quick sort  
def quick_sort(A, p, r):  
    &#39;&#39;&#39;&#39;&#39; 
        快速排序的最差时间复杂度为O(n2),平时时间复杂度为O(nlgn) 
    &#39;&#39;&#39;  
    if p < r:  
        q = partition2(A, p, r)  
        quick_sort(A, p, q-1)  
        quick_sort(A, q+1, r)  
   
if __name__ == &#39;__main__&#39;:  
   
    A = [5,-4,6,3,7,11,1,2]  
    print &#39;Before sort:&#39;,A  
    quick_sort(A, 0, 7)  
    print &#39;After sort:&#39;,A
ログイン後にコピー

不稳定,时间复杂度 最理想 O(nlogn)最差时间O(n^2)

说下python中的序列:

列表、元组和字符串都是序列,但是序列是什么,它们为什么如此特别呢?序列的两个主要特点是索引操作符和切片操作符。索引操作符让我们可以从序列中抓取一个特定项目。切片操作符让我们能够获取序列的一个切片,即一部分序列,如:a = ['aa','bb','cc'], print a[0] 为索引操作,print a[0:2]为切片操作。


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート