排序演算法(三)冒泡、選擇排序的Python實現及演算法最佳化詳解

來源:互聯網
上載者:User

標籤: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實現及演算法最佳化詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.