手撕程式碼之常用排序演算法

  • 2019 年 10 月 6 日
  • 筆記

手撕程式碼之常用排序演算法

0.導語

本節為手撕程式碼系列之第一彈,主要來手撕排序演算法,主要包括以下幾大排序演算法:

  • 直接插入排序
  • 冒泡排序
  • 選擇排序
  • 快速排序
  • 希爾排序
  • 堆排序
  • 歸併排序

1.直接插入排序

演算法思想

每一步將一個待排序的記錄,插入到前面已經排好序的有序序列中去,直到插完所有元素為止。

程式碼實現

# 直接插入排序  def insert_sort(arr):      length = len(arr)      for i in range(length):          k = i          for j in range(k,0,-1):              if arr[j]<arr[j-1]:                  t = arr[j]                  arr[j]=arr[j-1]                  arr[j-1]=t  arr = [4,3,0,-1]  insert_sort(arr)  print(arr)  

2.冒泡排序

演算法思想

對相鄰的元素進行兩兩比較,順序相反則進行交換,這樣,每一趟會將最小或最大的元素「浮」到頂端,最終達到完全有序。

程式碼實現

# 冒泡排序  def bubbleSort(arr):      length = len(arr)      for i in range(length-1):          flag = True          for j in range(length-i-1):              if arr[j]>arr[j+1]:                  t = arr[j]                  arr[j]=arr[j+1]                  arr[j+1]=t                  flag = False          if flag:              break  arr = [6,-2,0,9]  bubbleSort(arr)  print(arr)  

3.選擇排序

演算法思想

每一趟從待排序的數據元素中選擇最小(或最大)的一個元素作為首元素,直到所有元素排完為止,簡單選擇排序是不穩定排序

程式碼實現

def selectSort(arr):      length = len(arr)      for i in range(length-1):          min = i          for j in range(i+1,length):              if arr[min]>arr[j]:                  min=j          if min!=i:              t = arr[i]              arr[i]=arr[min]              arr[min]=t  arr = [6,-2,0,9]  selectSort(arr)  print(arr)  

4.快速排序

演算法思想

快速排序思想—-分治法。

  • 先從數列中取出一個數作為基準數。
  • 分區過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。
  • 再對左右區間重複第二步,直到各區間只有一個數。

每次劃分得到,樞椎的左邊比它小,右邊比它大。

程式碼實現

def quickSort(arr,left,right):      # 遞歸終止條件      if left>right:          return      pivot = arr[left]      i = left      j = right      while i<j:          while i<j and arr[j]>=pivot:              j-=1          while i<j and arr[i]<=pivot:              i+=1          if i<j:              t = arr[i]              arr[i] = arr[j]              arr[j] = t      # 放入樞椎      arr[left] = arr[i]      arr[i]=pivot      # 遞歸調用左區域      quickSort(arr,left,i-1)      # 遞歸調用右區域      quickSort(arr,i+1,right)    arr = [6,-2,0,9]  quickSort(arr,0,len(arr)-1)  print(arr)  

5.希爾排序

演算法思想

該演算法也被稱為:縮小增量排序

希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,演算法便終止。

程式碼實現

# 希爾排序  def shellSort(arr):      length =  len(arr)      # 設置初始增量      gap = length//2      while gap>0:          # 從第gap個元素,逐個對其所在組進行直接插入排序          for i in range(gap,length):              j = i              while j-gap>=0 and arr[j]<arr[j-gap]:                  t = arr[j]                  arr[j] = arr[j-gap]                  arr[j-gap] = t                  j-=gap          gap//=2  arr = [6,-2,0,9]  shellSort(arr)  print(arr)  

6.堆排序

演算法思想

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

基本思路:

  a.將無需序列構建成一個堆,根據升序降序需求選擇大頂堆或小頂堆;

  b.將堆頂元素與末尾元素交換,將最大元素"沉"到數組末端;(升序方法)

  c.重新調整結構,使其滿足堆定義,然後繼續交換堆頂元素與當前末尾元素,反覆執行調整+交換步驟,直到整個序列有序。

程式碼實現

class HeapSort:      def heapSort(self, nums):          length = len(nums)          # 從後往前遍歷,交換堆頂與最後葉子節點,並依次調整堆,重複操作          for j in range(length-1,0,-1):              # 獲取堆頂元素(獲取同時,調整堆)              firstNum = self.adjustHeap(nums,j+1)              # 交換最後一個葉子節點與堆頂元素              temp = nums[j]              nums[j] = firstNum              nums[0] = temp          return nums      # 調整堆(最大堆),每次返回最大堆頂元素      def adjustHeap(self,nums,length):          # 最後一個非葉節點          i = length//2 -1          # 從最後一個非葉節點開始調整,構成最大堆          while i>=0:              temp = nums[i]              k = 2*i+1              while k<length:                  if k+1<length and nums[k]<nums[k+1]:                      k+=1                  if nums[k]>temp:                      nums[i]=nums[k]                      i=k                  else:                      break                  k=2*k+1              nums[i] = temp              i-=1          return nums[0]  s = HeapSort()  nums = [8,9,7,10]  t = s.heapSort(nums)  print(t)  

7.歸併排序

演算法思想

歸併排序是利用歸併的思想實現的排序方法,該演算法採用經典的分治策略(分治法將問題(divide)成一些小的問題然後遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。

程式碼實現

def mergeSort(nums):      if len(nums)<=1:          return nums      mid = len(nums)//2      left = mergeSort(nums[:mid])      right = mergeSort(nums[mid:])      return merge(left,right)  def merge(left,right):      result = []      i,j = 0,0      while i<len(left) and j<len(right):          if left[i]<=right[j]:              result.append(left[i])              i+=1          else:              result.append(right[j])              j+=1      if i<len(left):          result+=left[i:]      if j<len(right):          result+=right[j:]      return result  nums = [5,3,0,6,1,4]  t = mergeSort(nums)  print(t)