一、数组元素与target比较划分区域
1.问题描述
给定一个target(目标值),依次和数组中的每一个数比较,如果小于或者等于target 就放进数组的左端,否则(也就是大于target),放在数组的右端。也就是把数组分成了两部分
2.思路
引入一个指针变量Less,指针变量左边的数全都是小于等于target,否则都放在指针变量的右边,这样既可完成划分。
步骤:
- 若cur(当前时刻的元素取值)≤ target,则cur与小于等于区域外的第一个数交换;然后小于等于区域扩大一个位置(即Less + 1);最后cur + 1
- 若cur(当前时刻的元素取值)≥ target,什么也不操作,直接cur + 1
3.python实现
def sort_area(array, L, R, target):
'''
问题一:
给定一个target,依次和数组中的每一个数比较,如果小于或者等于target 就放进数组的左端,
否则(也就是大于target),放在数组的右端。 也就是把数组分成了两部分
'''
cur = L
Less = L - 1
while cur < R:
if array[cur] <= target:
array[Less+1], array[cur] = array[cur], array[Less+1]
Less += 1
cur += 1
else:
cur += 1
return array[0:Less+1], array[Less+1:]
arr = [3, 4, 6, 1, 8, 0]
less_arr, more_arr = sort_area(arr, 0, len(arr), 4)
print('小于等于域:', less_arr,' 大于域:', more_arr)
二、荷兰国旗问题
1.问题描述
与问题一是同类型的,唯一不同的是这个问题是三个区域,也就是大于target、小于target、等于target
2.思路
相比于问题一,只需要多设置一个区域指针,左边设置为小于区域Less,中间设置为等于区域,右边设置为大于区域More。当cur指针碰到了more指针以后就停止即可(终止条件)。
步骤:
- 若cur == num,则不必做操作,cur += 1
- 若cur < num ,则cur与小于区域外的第一个数交换;然后小于区域扩大一个(less++,cur++)
- 若cur > num, 则cur与大于区域的前一个数交换;大于区域向左扩充一个位置(more++);然后因为是从后面换到前面的,这个数还没有做过比较判断,因此不能让cur++,而是应该保留当前cur然后回去继续比较!!!
- 停止条件:cur与more撞上即停止
3.python实现
def Dutch_flag(array, L, R, target):
'''
问题二,荷兰国旗问题:
与问题一是同类型的,唯一不同的是这个问题是三个区域,也就是大于target、小于target、等于target
相比于问题一,只需要多设置一个区域指针,左边设置为小于区域,中间设置为等于区域,右边设置为大于区域
当cur指针碰到了more指针以后 就停止即可
'''
cur = L
Less = L - 1
more = R + 1
while cur < more-1:
print('cur', cur)
if array[cur] < target:
array[Less+1], array[cur] = array[cur], array[Less+1]
Less += 1
cur += 1
if array[cur] > target:
array[more-1], array[cur] = array[cur], array[more-1]
more -= 1
print('more', more)
if array[cur] == target:
cur += 1
return array[L:Less+1], array[more:], array[Less+1:more]
arr = [3, 4, 5, 1, 8, 0, 6, 1, 5, 5, 9, 28]
less_arr, more_arr, equal_arr = Dutch_flag(arr, 0, len(arr)-1, 5)
print('小于域:', less_arr,' 大于域:', more_arr, '等于域:', equal_arr)
三、改进后的经典快排
1.问题描述
a.先说一下最原始的经典快排
(1)取数组的最后一个数(也可以取第一个数)记为x作为target,小于等于x的放在左边,大于x的放在右边;
(2)完成一次操作以后再把区域放缩,再次选取最后一个数记为a,依然小于等于的放左边,大于a的放右边(递归);在大于区域做同样的操作。
(3)递归,系统依次重复执行此操作
b.改进后的经典快排
它与最原始的经典快排的唯一区别就是前者的区域是两个区域,后者的区域是三个区域。因为如果把小于等于放在一起,那么一次只能搞定一个数,如果数据中有多个重复的数,那么一次只搞定了其中的一个,剩下的还混在了小于区域里面。而如果我们把小于等于分开,那么我们一次就搞定了一片数,效率自然会有提高。
2.python实现
ef quickSort(arr, L, R):
'''
改进后的快排快排
问题三:
改进后的经典快排与原始的经典的快排的区别就是,改进后的是分为了三个区域(小于、等于、大于),
因此每次挑出来的参照x都可以搞定一片(只要相等的都会搞定)。但是经典的只能搞定一个,因为它把小于和等于放一起了。
'''
if L < R:
small_index, large_index = partition(arr, L, R)
quickSort(arr, L, small_index-1)
quickSort(arr, large_index+1, R)
return arr
def partition(array, L, R):
'''
给定一个target,依次和数组中的每一个数比较,如果小于或者等于target 就放进数组的左端,
否则(也就是大于target),放在数组的右端。 也就是把数组分成了两部分
'''
cur = L
Less = L - 1
more = R + 1
target = array[R]
while cur < more:
if array[cur] < target:
array[Less+1], array[cur] = array[cur], array[Less+1]
Less += 1
cur += 1
if array[cur] > target:
array[more-1], array[cur] = array[cur], array[more-1]
more -= 1
if array[cur] == target:
cur += 1
return Less+1, more-1
arr = [1,21515,3,1255,5,77,7,7,5]
fianlArr = quickSort(arr, 0, len(arr)-1)
print(fianlArr)
四、随机快排(非常重要)
1.问题描述
相比于经典快排,无非就是加了一个概率。也就是说之前的数(target)要么取的是第一个数,要么取的是最后一个数,但是现在变成了随机选取target。
2.优势
因为经典快排分为最好、最坏情况,与数据情况有关,即若区域规模相差非常大,则有可能变成O(N^2),这样非常不好。那么如果我们加一个概率进去,,每次随机选数然后和数组的最后一个值交换,这样就加了一个概率时间。原先的不论最坏还是最好情况,现在都变成了一个概率问题,那么就得按照期望来看,因此就变成了O(logN)。
注意:因此我们可知,如果一种算法受数据情况的影响,那么我们可以从随机出发,消除数据最好最坏情况的影响。
3.python实现
import random
def randomQuickSort(arr, L, R):
'''
随机快排
加了个概率,使得最坏最好情况等概率,这样大数据的情况下时间复杂度期望就是O(NlogN)
'''
if L < R:
random_tmp = L + int(random.random()*(R - L + 1)) #与改进后的经典快排唯一的区别,就是选择数随机选取,然后再与最后一个数交换,以此往复
arr[R], arr[random_tmp] =arr[random_tmp], arr[R]
small_index, large_index = partition(arr, L, R)
randomQuickSort(arr, L, small_index-1)
randomQuickSort(arr, large_index+1, R)
return arr
def partition(array, L, R):
'''
问题一:
给定一个target,依次和数组中的每一个数比较,如果小于或者等于target 就放进数组的左端,
否则(也就是大于target),放在数组的右端。 也就是把数组分成了两部分
'''
cur = L
Less = L - 1
more = R + 1
target = array[R]
while cur < more:
if array[cur] < target:
array[Less+1], array[cur] = array[cur], array[Less+1]
Less += 1
cur += 1
if array[cur] > target:
array[more-1], array[cur] = array[cur], array[more-1]
more -= 1
if array[cur] == target:
cur += 1
return Less+1, more-1
arr = [1,21515,3,1255,5,77,7,7,5]
fianlArr = randomQuickSort(arr, 0, len(arr)-1)
print(fianlArr)