幾種基礎排序演算法的python實現

  • 2019 年 10 月 6 日
  • 筆記

最近利用晚上閑下來的時間整理了一些基礎的排序演算法,這些排序演算法一般的就是在學習數據結構的時候都是要求掌握的,作為一個開發者來說,會排序那是最基礎的技能,也是最重要的技能,下面我們就一起來看看吧!

插入排序

插入排序思想:每一趟將一個待排序元素,按其排序碼大小插入到前面已經排好序的一組元素的適當位置上,直到所有待排序元素元素全部插入為止

思路:

假定前i個構成的子序列是處於已排序的情況下進行排序的,然後將第i個元素與前i個構成的子序列逆序進行比較,如果是要升序排序,則比較第i個元素是否比j=i-1(i-1需要>=0)的元素大,如果是則第i個元素的位置(即j+1的位置上)保持不動,反之則將j=i-1的元素放置到i的位置,再進行第i個元素與j=i-2(i-2需要>=0)的,依次進行,如果第i個元素剛好比j=i-3大,則將第i個元素插入到j=i-2(即j+1的位置)上。

程式碼:

def insertion_sort(a):      l = len(a)      j = 0      for i in range(1, l):          temp = a[i]          for j in range(i - 1, -1, -1):              if temp < a[j]:  # 如果第i個元素大於前i個元素中的第j個                  a[j + 1] = a[j]  # 則第j個元素先後移1位              else:  # 如果第i個元素小於等於前i個元素中的第j個則結束循環                  break          a[j + 1] = temp  # 將i個元素賦值給空著的位置      for i in range(0, l):          print(a[i])

快速排序

思路:

任意選取一個數據(通常選用數組的第一個數)作為關鍵數據,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一趟快速排序。

一趟快速排序的演算法是:

1)設置兩個變數i、j,排序開始的時候:i=0,j=N-1;

2)以第一個數組元素作為關鍵數據,賦值給key,即key=A[0];

3)從j開始向前搜索,即由後開始向前搜索(j–),找到第一個小於key的值A[j],將A[j]和A[i]互換;

4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]互換;

5)重複第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)

程式碼,使用遞歸演算法來實現:

def quick_sort(arr, low, high):      # temp = a[0]      i = low      j = high      if i >= j:          return arr      temp = arr[i]      while i < j:          while i < j and arr[j] >= temp:              j = j - 1          arr[i] = arr[j]          while i < j and arr[i] <= temp:              i = i + 1          arr[j] = arr[i]      arr[i] = temp      quick_sort(arr, low, i - 1)      quick_sort(arr, j + 1, high)      return arr

冒泡排序

思路:

比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。

對每一對相鄰元素做同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。

針對所有的元素重複以上的步驟,除了最後一個。

持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。

程式碼:

def bubble_sort(arr):      length = len(arr)      while length > 0:          for i in range(length - 1):              if arr[i] > arr[i + 1]:                  arr[i] = arr[i] + arr[i + 1]                  arr[i + 1] = arr[i] - arr[i + 1]                  arr[i] = arr[i] - arr[i + 1]          length -= 1

選擇排序

思路:

每一趟從待排序的數據元素中選出最小(最大)的元素,順序放在待排序的數列最前,直到全部待排序的數據元素全部排完。

例子: [4, 2, 3] 找出最小的:2,與第一個元素交換 [2, 4, 3] 找出最小的:3,與第二個元素交換 [2, 3, 4]

程式碼:

def selection_sort(a):      for j in range(0,len(a)-1):          count = j  #記錄最小元素下標          #每次找出最小元素          for i in range(j,len(a)-1):              if a[count] > a[i+1]:                  count = i+1              #python特有的交換值方法,交換最小元素和待排序元素中最前一個          a[j], a[count] = a[count], a[j]      for i in range(0,len(a)):              print(a[i])

堆排序

先介紹一下堆,堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。如下圖:

思路:

將待排序序列構造成一個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將其與末尾元素進行交換,此時末尾就為最大值。然後將剩餘n-1個元素重新構造成一個堆,這樣會得到n個元素的次小值。如此反覆執行,便能得到一個有序序列了

堆排序是利用堆這種數據結構而設計的一種排序演算法,堆排序是一種選擇排序,它的最壞,最好,平均時間複雜度均為O(nlogn),它也是不穩定排序。首先簡單了解下堆結構。

在排序之前我們需要構造一個大頂堆,之後再使用堆排序

程式碼:

def adjustHead(a, i, l):      temp = a[i] #取出當前元素      k = 2*i + 1 #從左子節點開始,即2*i+1      while k < l:          if k+1 < l & a[k] < a[k+1]: #若果左子節點小於右子節點,k指向右子節點              k=k+1          if a[k] > temp:              a[i] = a[k]              i = k          else:              break          k = 2*k + 1 #把該節點當作父節點,繼續操作      a[i] = temp #將父節點值賦值給該子節點      def heap_sort(arr):      l = len(arr)      for i in range(int(l/2-1), -1, -1):          adjustHead(arr,i,l)        # 交換堆頂和最後一個元素,並調整堆結構      for j in range(l-1, 0, -1):          arr[0], arr[j] = arr[j], arr[0] #將堆頂元素和末尾元素進行交換          adjustHead(arr, 0, j) #重新對對進行調整      for k in range(0,l):          print(arr[k])

基數排序

基數排序又稱為「桶子法」,從低位開始將待排序的數按照這一位的值放到相應的編號為0~9的桶中。等到低位排完得到一個子序列,再將這個序列按照次低位的大小進入相應的桶中,一直排到最高位為止,數組排序完成。

思路:

(1)遍歷序列找出最大的數(為的是確定最大的數是幾位數);

(2)開闢一個與數組大小相同的臨時數組tmp;

(3)用一個count數組統計原數組中某一位(從低位向高位統計)相同的數據出現的次數;

(4)用一個start數組計算原數組中某一位(從最低位向最高位計算)相同數據出現的位置;

(5)將桶中數據從小到大用tmp數組收集起來;

(6)重複(3)(4)(5)直到所有位都被統計並計算過,用tmp收集起來;

(7)將tmp數組拷回到原數組中;

程式碼:

import math    def radix_sort(arr):      radix = 10 #基數      # k可以表示任意整數      k = int(math.ceil(math.log(max(arr),radix)))      #math.log對arr中最大的數取對數,log(max(arr),10),並對其取整得到最大值的位數      bucket =[[] for i in range(radix)]      for i in range(1, k+1):          for  value in arr:              # 析取整數第k位數字(從低到高)10**2位10的二次方              bucket[int(value%(radix**i)/(radix**(i-1)))].append(value)          del arr[:]          for each in bucket:              arr.extend(each) #桶合併          bucket = [[]for i in range(radix)]