下面介绍两个时间复杂度都是 O(nlogn) 的排序算法。
快速排序(分治策略)
令 l,r 分别代表序列最小下标值和最大下标值
让这两个指针一个从左往右,一个从右往左,分别查找,当 l < r 开始循环:
1.当右边数 arr[r]大于基准数,右指针-1 继续向左查找,如果找到比基准数小就与左边的数arr[l]交换位置
2.当左边数 arr[l]小于基准数,左指针+1 继续向右查找,如果找到比基准数大就与右边的数arr[r]交换位置
3.当l = r 即左右下标指向同一个数说明序列已经遍历一遍,这个位置就是一个分界(左边都是小于基准值的,右边都是大于基准值的),就把基准数放在这个位置(令arr[l]=key)
4.然后对前面步骤将序列分成的两子部分进行递归排序
def quickSort(arr,l,r):
if l>=r:#递归边界
return arr
key=arr[l]
low=l
high=r
while l<r:
while l<r and arr[r]>=key:
r-=1 #大于等于基准值时继续往左查找
arr[l]=arr[r] #小于基准值时就交换位置
while l<r and arr[l]<=key:
l+=1 #小于等于基准值时继续往右查找
arr[r]=arr[l] #大于基准值时就交换位置
arr[l]=key # l=r时即左右下标指向同一个数说明序列已经遍历一遍,
# 这个位置就是一个分界(左边都是小于基准值的,右边都是大于基准值的),故令arr[l]=key
# 再对前面步骤将序列分成的两子部分进行迭代排序
quickSort(arr,low,l-1)
quickSort(arr,l+1,high)
java版:
public int[] quickSort(int[] arr , int l, int r){
if (l>=r) {
return arr;
}
int key = arr[l];
int low = l;
int hight = r;
while(l < r){
while(l < r && arr[r] >= key){
r -= 1;
}
arr[l] = arr[r];
while(l < r && arr[l] <= key){
l += 1;
}
arr[r] = arr[l];
}
arr[l] = key;
quickSort(arr,low,l - 1);
quickSort(arr,l + 1,hight);
return arr;
}
二分归并排序(分治策略)
先将数组通过二分法递归地分成n个子式,再调用合并函数进行合并。
如果左子式小于右子式,就将左子式添加到list集合中,指针前移一位;
如果右子式小于左子式,就将右子式添加到list集合中,指针前移一位,
只要左子式指针和右子式指针都小于各自子式的长度,就这样循环比较下去。
因为递归二分之后可能会存在左子式比右子式多或者右子式比左子式多的情况,所以
如果左子式走完了,就将右子式的剩余元素添加到集合中(因为经过层层递归子式内部一定是有序的),否则将左子式剩余元素添加到集合中,最后返回最终结果集合就可以了。
def merge(a,b):
c=[]#记录合并结果
h=j=0
while j<len(a) and h<len(b):
if a[j]<b[h]:
c.append(a[j])
j+=1
else:
c.append(b[h])
h+=1
if j==len(a):
for i in b[h:]:
c.append(i)
else:
for i in a[j:]:
c.append(i)
return c
def mergeSort(arr):
if len(arr)<=1:
return arr
middle=len(arr)//2
left=mergeSort(arr[:middle])
right=mergeSort(arr[middle:])
return merge(left,right)