標籤:python 冒泡法 選擇排序
說在前面
最近一年太忙,部落格長草了。近日用Python實現了常用排序演算法,供大家參考。
Java版本排序演算法及最佳化,請看以前的文章。
《排序演算法之簡單排序(冒泡、選擇、插入)》
《排序演算法(二)堆排序》
1、排序概念
這裡不再贅述,請參看前面2篇文章
2、簡單排序之冒泡法Python實現及最佳化
原理圖
650) this.width=650;" src="https://s1.51cto.com/wyfs02/M02/07/40/wKiom1nF8CTRGF7IAACgLGM-eko688.png" title="冒泡法原理圖1" width="700" height="283" border="0" hspace="0" vspace="0" style="width:700px;height:283px;" alt="wKiom1nF8CTRGF7IAACgLGM-eko688.png" />
650) this.width=650;" src="https://s1.51cto.com/wyfs02/M00/A5/F1/wKioL1nF8Cix7ybrAAByZegzjnI171.png" title="冒泡法原理圖2" width="700" height="131" border="0" hspace="0" vspace="0" style="width:700px;height:131px;" alt="wKioL1nF8Cix7ybrAAByZegzjnI171.png" />
2.1、基本實現
num_list = [ [1, 9, 8, 5, 6, 7, 4, 3, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9]]nums = num_list[1]print(nums)length = len(nums)count_swap = 0count = 0# bubble_sortfor i in range(length): for j in range(length-i-1): count += 1 if nums[j] > nums[j+1]: tmp = nums[j] nums[j] = nums[j+1] nums[j+1] = tmp count_swap += 1print(nums, count_swap, count)
2.2、最佳化實現
思路:如果本輪有互動,就說明順序不對;如果本輪無交換,說明是目標順序,直接結束排序。
num_list = [ [1, 9, 8, 5, 6, 7, 4, 3, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 9, 8]]nums = num_list[2]print(nums)length = len(nums)count_swap = 0count = 0# bubble_sortfor i in range(length): flag = False for j in range(length-i-1): count += 1 if nums[j] > nums[j+1]: tmp = nums[j] nums[j] = nums[j+1] nums[j+1] = tmp flag = True # swapped count_swap += 1 if not flag: breakprint(nums, count_swap, count)
總結:
冒泡法需要資料一輪輪比較。
最佳化,則可設定一個標記判斷此輪是否有資料交換髮生,如果沒有發生交換,可以結束排序,如果發生交換,繼續下一輪排序
最差的排序情況是,初始順序與目標順序完全相反,遍曆次數1,...,n-1之和n(n-1)/2
最好的排序情況是,初始順序與目標順序完全相同,遍曆次數n-1
時間複雜度O(n^2)
3、簡單排序之選擇排序Python實現及最佳化
選擇排序的核心:每一輪比較找到一個極值(最大值或最小值)放到某一端,對剩下的數再找極值,直至比較結束。
原理圖
650) this.width=650;" src="https://s3.51cto.com/wyfs02/M02/A5/F1/wKioL1nF8Frhx7cIAAC8VirJv_A194.png" title="選擇排序原理圖" width="700" height="304" border="0" hspace="0" vspace="0" style="width:700px;height:304px;" alt="wKioL1nF8Frhx7cIAAC8VirJv_A194.png" />
3.1、基本實現
m_list = [ [1, 9, 8, 5, 6, 7, 4, 3, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1]]nums = m_list[0]length = len(nums)print(nums)count_swap = 0count_iter = 0for i in range(length): maxindex = i for j in range(i + 1, length): count_iter += 1 if nums[maxindex] < nums[j]: maxindex = j if i != maxindex: tmp = nums[i] nums[i] = nums[maxindex] nums[maxindex] = tmp count_swap += 1print(nums, count_swap, count_iter)
3.2、最佳化實現——二元選擇排序
思路:減少迭代次數,一輪確定2個數,即最大數和最小數。
m_list = [ [1, 9, 8, 5, 6, 7, 4, 3, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1]]nums = m_list[3]length = len(nums)print(nums)count_swap = 0count_iter = 0# 二元選擇排序for i in range(length // 2): maxindex = i minindex = -i - 1 minorigin = minindex for j in range(i + 1, length - i): # 每次左右都要少比較一個 count_iter += 1 if nums[maxindex] < nums[j]: maxindex = j if nums[minindex] > nums[-j - 1]: minindex = -j - 1 #print(maxindex,minindex) if i != maxindex: tmp = nums[i] nums[i] = nums[maxindex] nums[maxindex] = tmp count_swap += 1 # 如果最小值被交換過,要更新索引 if i == minindex or i == length + minindex: minindex = maxindex if minorigin != minindex: tmp = nums[minorigin] nums[minorigin] = nums[minindex] nums[minindex] = tmp count_swap += 1print(nums, count_swap, count_iter)
3.3、等值情況最佳化
思路:二元選擇排序的時候,每一輪可以知道最大值和最小值,如果某一輪最大最小值都一樣了,說明剩下的數字都是相等的,直接結束排序。
m_list = [ [1, 9, 8, 5, 6, 7, 4, 3, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1]]nums = m_list[3]length = len(nums)print(nums)count_swap = 0count_iter = 0# 二元選擇排序for i in range(length // 2): maxindex = i minindex = -i - 1 minorigin = minindex for j in range(i + 1, length - i): # 每次左右都要少比較一個 count_iter += 1 if nums[maxindex] < nums[j]: maxindex = j if nums[minindex] > nums[-j - 1]: minindex = -j - 1 #print(maxindex,minindex) if nums[maxindex] == nums[minindex]: # 元素相同 break if i != maxindex: tmp = nums[i] nums[i] = nums[maxindex] nums[maxindex] = tmp count_swap += 1 # 如果最小值被交換過,要更新索引 if i == minindex or i == length + minindex: minindex = maxindex if minorigin != minindex: tmp = nums[minorigin] nums[minorigin] = nums[minindex] nums[minindex] = tmp count_swap += 1print(nums, count_swap, count_iter)
3.4、等值情況最佳化進階
思路:
[1, 1, 1, 1, 1, 1, 1, 1, 2] 這種情況,找到的最小值索引是-2,最大值索引8,上面的代碼會交換2次,最小值兩個1交換是無用功,所以,增加一個判斷。
m_list = [ [1, 9, 8, 5, 6, 7, 4, 3, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 2]]nums = m_list[4]length = len(nums)print(nums)count_swap = 0count_iter = 0# 二元選擇排序for i in range(length // 2): maxindex = i minindex = -i - 1 minorigin = minindex for j in range(i + 1, length - i): # 每次左右都要少比較一個 count_iter += 1 if nums[maxindex] < nums[j]: maxindex = j if nums[minindex] > nums[-j - 1]: minindex = -j - 1 print(maxindex,minindex) if nums[maxindex] == nums[minindex]: # 元素相同 break if i != maxindex: tmp = nums[i] nums[i] = nums[maxindex] nums[maxindex] = tmp count_swap += 1 # 如果最小值被交換過,要更新索引 if i == minindex or i == length + minindex: minindex = maxindex # 最小值索引不同,但值相同就沒有必要交換了 if minorigin != minindex and nums[minorigin] != nums[minindex]: tmp = nums[minorigin] nums[minorigin] = nums[minindex] nums[minindex] = tmp count_swap += 1 print(nums, count_swap, count_iter)
還可能存在一些特殊情況可以最佳化,但是都屬於特例的最佳化了,對整個演算法的提升有限。
總結
簡單選擇排序需要資料一輪輪比較,並在每一輪中發現極值
沒有辦法知道當前輪是否已經達到排序要求,但是可以知道極值是否在目標索引位置上
遍曆次數1,...,n-1之和n(n-1)/2
時間複雜度O(n^2)
減少了交換次數,提高了效率,效能略好於冒泡法
本文出自 “終南山下” 部落格,謝絕轉載!
排序演算法(三)冒泡、選擇排序的Python實現及演算法最佳化詳解