堆排序和歸併排序以及快速排序是比較經典的排序方法。堆排序的時間複雜度是nlogn,歸併排序的時間複雜度可以達到O(n),快速排序的時間複雜度是nlogn。可見歸併排序的排序速度比較快,但是比較耗費內存,畢竟是通過遞歸的方式來切分待排序序列。
堆排序可以參考我的上一篇博客。歸併排序從字面意思來看,有兩個過程:“歸”和“並”。“歸”是遞歸的意思,“並”當然是合併的意思。
“歸”。遞歸是歸併排序的核心思想。其基本思想是對於一個無序的序列我們總是可以將它一分爲二。直到切分出來的序列有序。按照這個分法,我們總可以通過有限步的切分,將待排序序列切分成若干個有序的子序列。然後通過遞歸的逆過程,將切分出來的有序子序列進行合併。下面給出一個例子:
對序列 sequence = [9, 5 , 7, 2]進行歸併排序。序列切分方法:left = len(sequence ) // 2
1、left_sequence = [9, 5] right_sequence = [7, 2]
顯然left_sequence 是沒有順序的,需要按照上面的方法繼續進行切分。
2、left_sequence_1 = [9] right_sequence_1 = [5]
顯然 left_sequence_1 和 right_sequence_1 都是有順序的序列。我們不再對其進行切分
3、left_sequence_2 = [7] right_sequence_2 = [2]
顯然 left_sequence_2 和 right_sequence_2 都是有順序的序列。我們不再對其進行切分
通過這3步,遞歸過程就完成了。
“並”。遞歸的逆過程。通過上面的例子,我們可以很清楚的看到總共切分除了4個子序列。將 left_sequence_2 和 right_sequence_2進行合併。這裏需要提一下,合併的方法有很多。最有效的方法可能就是下面的這種形式:
while left_index < len(left_sequence_2):
right_sequence_2.append[right_sequence_2[0]] # 從上個序列取出的元素必須要放到第二個序列中。
while right_index < len(right_sequence_2) - 1: # 減1,sequence_2最後一個元素不需要比較
if right_sequence_2[right_index] < left_sequence_2[left_index]:
right_index += 1
else:
right_sequence_2中的元素從right_index索引對應的元素開始後移
right_sequence_2[right_index] = left_sequence_2[left_index]
第一次合併產生的序列:[5, 9]
第二次合併產生的序列:[2, 7]
第三次合併產生的序列:[2,5,,7,9]
下面給出使用python編制的歸併排序的代碼:
import sys class Solution: def __init__(self): pass def getdata(self): read_line = sys.stdin.readline().split() read_line = list(map(lambda x: int(x), read_line)) return read_line def gbpx(self, data): assert hasattr(data, '__len__') assert len(data) > 0 len_data = len(data) if len_data == 1: return data for cur_data_index in range(1, len_data, 1): if data[cur_data_index] < data[cur_data_index - 1]: middle = len_data // 2 left = data[:middle] # 9 5 right = data[middle:len_data] # 2 7 left_ordeted = self.gbpx(left) right_ordered = self.gbpx(right) print((left_ordeted, right_ordered)) index_left = 0 index_right = 0 while index_left < len(left_ordeted): right_ordered.append(right_ordered[0]) while index_right < len(right_ordered) - 1: if right_ordered[index_right] < left_ordeted[index_left]: index_right += 1 else: for mov_index in range(index_right, len(right_ordered), 1): right_ordered[mov_index], right_ordered[-1] = right_ordered[-1],\ right_ordered[mov_index] right_ordered[index_right] = left_ordeted[index_left] break right_ordered[index_right] = left_ordeted[index_left] index_left += 1 print('tmp:', right_ordered) return right_ordered return data if __name__ == '__main__': so = Solution() print(so.gbpx(so.getdata()))
結果:
7 4 1 5 8 9 6 2 1 4 7 5 1 ([4], [1]) tmp: [1, 4] ([7], [1, 4]) tmp: [1, 4, 7] ([1, 4, 7], [5, 8, 9]) tmp: [1, 5, 8, 9] tmp: [1, 4, 5, 8, 9] tmp: [1, 4, 5, 7, 8, 9] ([2], [1]) tmp: [1, 2] ([6], [1, 2]) tmp: [1, 2, 6] ([5], [1]) tmp: [1, 5] ([4, 7], [1, 5]) tmp: [1, 4, 5] tmp: [1, 4, 5, 7] ([1, 2, 6], [1, 4, 5, 7]) tmp: [1, 1, 4, 5, 7] tmp: [1, 1, 2, 4, 5, 7] tmp: [1, 1, 2, 4, 5, 6, 7] ([1, 4, 5, 7, 8, 9], [1, 1, 2, 4, 5, 6, 7]) tmp: [1, 1, 1, 2, 4, 5, 6, 7] tmp: [1, 1, 1, 2, 4, 4, 5, 6, 7] tmp: [1, 1, 1, 2, 4, 4, 5, 5, 6, 7] tmp: [1, 1, 1, 2, 4, 4, 5, 5, 6, 7, 7] tmp: [1, 1, 1, 2, 4, 4, 5, 5, 6, 7, 7, 8] tmp: [1, 1, 1, 2, 4, 4, 5, 5, 6, 7, 7, 8, 9] [1, 1, 1, 2, 4, 4, 5, 5, 6, 7, 7, 8, 9] Process finished with exit code 0