生活随笔
收集整理的這篇文章主要介紹了
Python数据结构学习笔记——搜索与排序算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- 一、搜索
- 二、排序
- 內排序和外排序
- (一)冒泡排序
- (二)選擇排序
- (三)插入排序
- (四)希爾排序
- (五)歸并排序
- (六)快速排序
- 總結
一、搜索
(一)搜索的方法
搜索是指從元素集合中找到某個特定元素的算法過程,搜索過程通常返回True或False,分別表示元素是否存在。Python中通過運算符in來檢查一個元素是否處于元素集合中,如下:
print("C" in ["C", "S", "D", "N"])
print("C" in (1, 2, 3))
print("c" in {"a": "A", "b": "B", "c": "C"})
print("c" in {1, "123", "ab"})
運行結果如下:
(二)順序搜索
以python中的列表為例,由于其各元素存在線性或順序的關系,每個元素都有一個唯一的下標,且下標是有序的,可以通過順序訪問,從而進行順序搜索。順序搜索的概念是從左到右依次查找元素,從第一個元素開始依次,若到列表末尾仍沒有查到則說明該元素不在列表中。
無序列表的順序搜索和有序列表的順序搜索的時間復雜度都是O(n),只有當列表中不存在要搜索的目標元素時,有序排列的元素的順序搜索的效率較高。
無序列表的順序搜索代碼如下:
def sequential_Search(alist
, item
): pos
= 0 found
= Falsewhile pos
< len(alist
) and not found
: if alist
[pos
] == item
: found
= Trueelse:pos
= pos
+ 1 return found
def orderedSequential_Search(alist
, item
): pos
= 0 found
= Falsestop
= Falsewhile pos
< len(alist
) and not found
and not stop
:if alist
[pos
] == item
: found
= Trueelse:if alist
[pos
] > item
: stop
= Trueelse:pos
= pos
+ 1 return found
print(sequential_Search
([6, 4, 5, 0], 6))
print(orderedSequential_Search
([1, 2, 3, 4, 5], 6))
運行結果如下:
(三)二分搜索
二分搜索相較于順序搜索,其不是從第一個元素開始搜索列表,而是從中間的元素著手,所以被稱為二分搜索。若這個元素就是要搜索的目標元素,則立即停止搜索;如果不是,則可以利用列表有序的特性,排除一半的元素,依次下去,直到搜索到目標元素。簡單的來說,也就是將一個大問題依次分成小問題,從而縮小范圍,依次解決。
對于有序列表來說,二分搜索算法在最壞情況下的時間復雜度是O(logn),有序列表的二分搜索代碼如下:
def binarySearch(alist
, item
): first
= 0last
= len(alist
) - 1 found
= Falsewhile first
<= last
and not found
:midpoint
= (first
+ last
) // 2 if alist
[midpoint
] == item
:found
= Trueelse:if item
< alist
[midpoint
]:last
= midpoint
- 1else:first
= midpoint
+ 1return found
print(binarySearch
([1, 6, 9, 10, 13, 14, 18], 14))
運行結果如下:
步驟解析:
二分搜索中運用遞歸方法進行改進,代碼如下:
def binarySearch(alist
, item
):if len(alist
) == 0:return Falseelse:midpoint
= len(alist
) // 2if alist
[midpoint
] == item
:return Trueelse:if item
< alist
[midpoint
]:return binarySearch
(alist
[:midpoint
], item
) else:return binarySearch
(alist
[midpoint
+ 1:], item
) print(binarySearch
([1, 6, 9, 10, 13, 14, 18], 14))
運行結果如下:
二、排序
內排序和外排序
根據待排序的內容是否在內存中可將排序分為內排序和外排序,內排序的整個排序過程在內存在進行,而外排序由于排序的內容太多,內存無法容納,需要借助外存,即其排序過程在內、外存之間交換數據才能進行。
(一)冒泡排序
冒泡排序通過兩兩比較相鄰元素,如果反序,即大的在前面小的在后面時則交換,小的元素被交換至前面,一直到沒有反序的情況為止,之所以叫做冒泡排序是因為在排序過程中,越小的元素會經過交換像一個個氣泡一樣浮到水面,即最小的元素會到數列的最前面,而最大的元素將會沉到數列的最底端。
冒泡排序中無論元素如何排列,給含有n個元素的列表進行冒泡排序需遍歷n-1輪,該算法的時間復雜度是O(n2),其中最好情況下,列表已處于有序不需要執行交換操作;而最壞情況下,每一次比較都將導致一次交換。
冒泡排序的程序代碼如下:
def BubbleSort(alist
):for passnum
in range(len(alist
) - 1, 0, -1): for i
in range(passnum
):if alist
[i
] > alist
[i
+ 1]: temp
= alist
[i
] alist
[i
] = alist
[i
+ 1] alist
[i
+ 1] = temp
print(alist
)BubbleSort
([3, 0, 1, 9, 10, -2])
運行結果如下:
具體的執行步驟如下:
1、由于python的特性,通過同時賦值將交換的三行語句直接替換為一條語句:
temp
= alist
[i
]
alist
[i
] = alist
[i
+ 1]
alist
[i
+ 1] = temp
替換為a,b=b,a的形式,從而直接交換:
alist
[i
], alist
[i
+ 1] = alist
[i
+ 1], alist
[i
]
def BubbleSort(alist
):for passnum
in range(len(alist
) - 1, 0, -1): for i
in range(passnum
):if alist
[i
] > alist
[i
+ 1]: alist
[i
], alist
[i
+ 1] = alist
[i
+ 1], alist
[i
] print(alist
)BubbleSort
([3, 0, 1, 9, 10, -2])
運行結果如下:
2、短冒泡
冒泡排序的效率很低,因為在確定最終的位置前必須交換元素,它遍歷了列表中未排序的部分。
若在一輪遍歷中沒有產生交換,則可以說明列表中的元素已經有序,此時可以通過修改程序使程序終止,稱為短冒泡排序,其中變量passnum控制循環的循環次數,從而在遍歷中沒有產生交換時終止,代碼如下:
def ShortBubbleSort(alist
):exchanges
= True passnum
= len(alist
) - 1 while passnum
> 0 and exchanges
:exchanges
= Falsefor i
in range(passnum
):if alist
[i
] > alist
[i
+ 1]:exchanges
= Truealist
[i
], alist
[i
+ 1] = alist
[i
+ 1], alist
[i
]passnum
= passnum
- 1print(alist
)ShortBubbleSort
([3, 0, 1, 9, 10, -2])
運行結果如下:
(二)選擇排序
選擇排序每次遍歷列表時只做一次交換,在每次遍歷時尋找最大值,并在遍歷完之后將它放到正確位置上。若給n個元素排序,需要遍歷n-1輪,這是因為最后一個元素要到n-1輪遍歷后才就位,該算法的時間復雜度也是O(n2)。
選擇排序的代碼如下:
def SelectSort(alist
):for i
in range(len(alist
) - 1, 0, -1): positionOfMax
= 0for location
in range(1, i
+ 1): if alist
[location
] > alist
[positionOfMax
]:positionOfMax
= locationalist
[i
], alist
[positionOfMax
] = alist
[positionOfMax
], alist
[i
]print(alist
)SelectSort
([9, 12, 0, -6, 7, 36, 1])
運行結果如下:
具體的執行步驟如下:
通過將冒泡排序和選擇排序比較,排序列表[9, 12, 0, -6, 7, 36, 1],選擇排序只交換了5次,而冒泡排序多達十幾次,因此選擇排序算法通常更快。
(三)插入排序
插入排序的原理是在列表的一端維護一個已有序的子列表,逐個將另一邊的元素插入至這個有序的列表中,每輪將當前元素與有序子列表中的元素進行比較,有序子列表中將比它的元素右移,遇到比它小的或到達子列表終點時,就將當前元素插入,最后使整個列表有序化,插入排序的時間復雜度也是O(n2)。
插入排序的代碼如下:
def InsertSort(alist
):for index
in range(1, len(alist
)): currentvalue
= alist
[index
]position
= index
while position
> 0 and alist
[position
- 1] > currentvalue
:alist
[position
] = alist
[position
- 1]position
= position
- 1alist
[position
] = currentvalue
print(alist
)print(InsertSort
([2, 0, 9, -3, 1, 4]))
運行結果如下:
具體的執行步驟如下,左邊標紅的數字為排列好的順序:
(四)希爾排序
希爾排序是經插入排序改進后的排序算法,它將排序的列表切分成多個子列表,然后對每一個子列表進行插入排序,其中切分列表使用一個增量(或步長)選取間隔為一定增量的元素組成子列表,增量為sublistcount = len(alist) // 2,然后縮小增量以sublistcount = sublistcount // 2繼續切分列表,最后再對此時增量為1的列表進行插入排序。
采用以下代碼的希爾排序的時間復雜度是O(n1)至O(n2)之間,希爾排序的程序代碼如下:
def ShellSort(alist
):sublistcount
= len(alist
) // 2 while sublistcount
> 0:for startposition
in range(sublistcount
):InsertSort
(alist
, startposition
, sublistcount
)print("當前選取增量:", sublistcount
, "當前列表順序:", alist
)sublistcount
= sublistcount
// 2 def InsertSort(alist
, start
, gap
): for i
in range(start
+ gap
, len(alist
), gap
):currentvalue
= alist
[i
]position
= i
while position
> 0 and alist
[position
- gap
] > currentvalue
:alist
[position
] = alist
[position
- gap
]position
= position
- gapalist
[position
] = currentvalueShellSort
([2, 0, 9, -3, 1, 4])
運行結果如下:
具體的執行步驟如下:
(五)歸并排序
歸并排序是一種遞歸算法,每次操作將當前列表一分為二進行拆分,若分開的子列表為空或只有一個元素時,則可以認為它是有序的;若子列表不為空則再將列表一分為二,對兩部分都遞歸調用歸并排序,依次進行下去,當對一分為二的兩部分子列表都有序后,再將其歸并為一個有序列表,即完成排序。
歸并排序的時間復雜度是O(nlogn),但是歸并過程需要用到額外的存儲空間,歸并排序的程序代碼如下:
def MergeSort(alist
):print("切分", alist
)if len(alist
) > 1: mid
= len(alist
) // 2 left_half
= alist
[:mid
] right_half
= alist
[mid
:] MergeSort
(left_half
) MergeSort
(right_half
) i
, j
, k
= 0, 0, 0while i
< len(left_half
) and j
< len(right_half
): if left_half
[i
] < right_half
[j
]:alist
[k
] = left_half
[i
]i
= i
+ 1else:alist
[k
] = right_half
[j
]j
= j
+ 1k
= k
+ 1while i
< len(left_half
):alist
[k
] = left_half
[i
]i
= i
+ 1k
= k
+ 1while j
< len(right_half
):alist
[k
] = right_half
[j
]j
= j
+ 1k
= k
+ 1print("歸并 ", alist
)MergeSort
([2, 0, 9, -3, 4, 1])
運行結果如下:
具體的執行步驟如下:
(六)快速排序
和歸并排序一樣,快速排序也是采用一分為二的方式,但它不會占用額外的存儲空間,不過列表可能不會被一分為二從而影響效率。
首先,快速排序會選出一個基準值用于切分列表,也就是分隔點;然后進行分區,將大于基準值和小于基準值的元素放在兩邊,其中leftmark和rightmark變量代表位于列表中剩余的所有元素的開頭元素和末尾元素。
快速排序的程序代碼如下:
def quickSort(alist
):quickSortHelper
(alist
, 0, len(alist
) - 1)print(alist
)def quickSortHelper(alist
, first
, last
): if first
< last
:splitpoint
= partition
(alist
, first
, last
)quickSortHelper
(alist
, first
, splitpoint
- 1)quickSortHelper
(alist
, splitpoint
+ 1, last
)def partition(alist
, first
, last
): pivotvalue
= alist
[first
]leftmark
= first
+ 1rightmark
= lastdone
= Falsewhile not done
:while leftmark
<= rightmark
and alist
[leftmark
] <= pivotvalue
:leftmark
= leftmark
+ 1while alist
[rightmark
] >= pivotvalue
and rightmark
>= leftmark
:rightmark
= rightmark
- 1if rightmark
< leftmark
:done
= Trueelse:alist
[leftmark
], alist
[rightmark
] = alist
[rightmark
], alist
[leftmark
]alist
[first
], alist
[rightmark
] = alist
[rightmark
], alist
[first
]return rightmarkquickSort
([2, 7, -1, 0, 9, -3, 4, 1])
運行結果如下:
具體的執行步驟如下:
總結
名稱時間復雜度
| 順序搜索 | 不論列表是否有序,都為O(n) |
| 二分搜索 | 對于有序列表,為O(logn) |
| 冒泡排序 | O(n2) |
| 選擇排序 | O(n2) |
| 插入排序 | O(n2) |
| 希爾排序 | 介于O(n)和O(n2)之間 |
| 歸并排序 | O(nlogn) |
| 快速排序 | O(nlogn),當切分點不靠近列表中部時會降低至O(n2) |
總結
以上是生活随笔為你收集整理的Python数据结构学习笔记——搜索与排序算法的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。