-
Notifications
You must be signed in to change notification settings - Fork 0
/
quicksort.py
159 lines (150 loc) · 5.65 KB
/
quicksort.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
nums = [23,2,4,6,2,5,1,6,13,54,8]
# ------------------快速排序A, 时间复杂度O(nlogn), 最坏的情况下O(n^2)-----------------------
# ------------------空间复杂度O(logn)-----------------------------------------------------
# ------------------不稳定排序------------------------------------------------------------
def quicksort(nums, left, right):
if left >= right:
return
pivot = left
i, j = left, right
while i < j:
while nums[pivot] <= nums[j] and i < j:
j -= 1
while nums[pivot] >= nums[i] and i < j:
i += 1
if i < j:
nums[i], nums[j] = nums[j], nums[i]
nums[pivot], nums[i] = nums[i], nums[pivot]
quicksort(nums, left, i-1)
quicksort(nums, i+1, right)
# ------------------快速排序B, 时间复杂度O(nlogn), 最坏的情况下O(n^2)-----------------------
def quicksort2(nums, left, right): # 用栈代替递归
if left >= right:
return
stack = []
while stack or left < right:
if left < right:
pivot = left
i, j = left, right
while i < j:
while nums[pivot] <= nums[j] and i < j:
j -= 1
while nums[pivot] >= nums[i] and i < j:
i += 1
if i < j:
nums[i], nums[j] = nums[j], nums[i]
nums[pivot], nums[i] = nums[i], nums[pivot]
stack.append((left, i, right))
right = i - 1
else:
left, mid, right = stack.pop()
left = mid + 1
quicksort2(nums, 0, len(nums)-1)
print(nums)
# ------------------------快速排序的优化----------------------------
# ------------------------A三数中值快速排序-----------------------------
def quicksort_opt1(nums, left, right):
if left >= right:
return
stack = []
while stack or left < right:
if left < right:
l, m, r = left, (right-left)//2, right # 第一个, 中间位置, 最后一个
pivot = findmedian(l, m, r) # 三数取中值法选取枢轴元pivot
i, j = left, right
while i < j:
while nums[pivot] <= nums[j] and i < j:
j -= 1
while nums[pivot] >= nums[i] and i < j:
i += 1
if i < j:
nums[i], nums[j] = nums[j], nums[i]
nums[pivot], nums[i] = nums[i], nums[pivot]
stack.append((left, i, right))
right = i - 1
else:
left, mid, right = stack.pop()
left = mid + 1
def findmedian(l, m, r):
if nums[l] <= nums[m]:
if nums[m] <= nums[r]:
return m
else:
if nums[l] >= nums[r]:
return l
else:
return r
else:
if nums[m] >= nums[r]:
return m
else:
if nums[l] >= nums[r]:
return r
else:
return l
# ------------------------快速排序重复元素处理-----------------------------
# ------------------------B双路快速排序-----------------------------------
def quicksort_opt2(nums, left, right):
if left >= right:
return
stack = []
while stack or left < right:
if left < right:
l, m, r = left, (right-left)//2, right # 第一个, 中间位置, 最后一个
pivot = findmedian(l, m, r) # 三数取中值法选取枢轴元pivot
nums[pivot], nums[left] = nums[left], nums[pivot]
pivot = left
i, j = left+1, right
while i <= j: # 为什么不能是 i < j?
# 此处先平移j和先平移i对结果没有影响
while nums[i] < nums[pivot] and i <= j:
#不能改为nums[i] <= nums[pivot], 因为这种方式将连续出现的这些值归为其中一方, 使得两棵树不平衡
i += 1
while nums[j] > nums[pivot] and i <= j:
j -= 1
if i <= j:
nums[i], nums[j] = nums[j], nums[i]
j -= 1
i += 1
nums[pivot], nums[j] = nums[j], nums[pivot]
#因为pivot放置在左边, 所以不可与左侧指针i交换---->会造成无限循环
stack.append((left, j, right))
right = j - 1
else:
left, mid, right = stack.pop()
left = mid + 1
nums = [23,2,4,6,2,5,1,6,13,54,8]
quicksort_opt2(nums, 0, len(nums)-1)
print(nums)
# ------------------------C三路快速排序-----------------------------------
def quicksort_opt3(nums, left, right):
if left >= right:
return
stack = []
while stack or left < right:
if left < right:
l, m, r = left, (right-left)//2, right
pivot = findmedian(l, m, r)
nums[pivot], nums[left] = nums[left], nums[pivot]
pivot = left
lt, gt = left, right + 1
i = left + 1
while i < gt:
if nums[i] < nums[pivot]:
nums[i], nums[lt+1] = nums[lt+1], nums[i]
i += 1
lt += 1
elif nums[i] > nums[pivot]:
nums[i], nums[gt-1] = nums[gt-1], nums[i]
gt -= 1
else:# nums[i] == nums[pivot]
i += 1
nums[pivot], nums[lt] = nums[lt], nums[pivot]
stack.append((left, lt, right))
right = lt - 1
else:
left, mid, right = stack.pop()
left = mid + 1
nums = [23,2,4,6,2,5,1,6,13,54,8]
quicksort_opt3(nums, 0, len(nums)-1)
print(nums)