快速排序
快速排序的算法思想是分治,主要有以下四个步骤
- 选取一个分界点,比如左端点,右端点或中间值
- 调整区间,让分界点左边的值都 < 分界点,分界点右边的值 > 分界点
- 递归处理左右区间
其中,比较复杂的一步就是第二步。如何调整区间呢?我们可以使用双指针l、r,分别从左右端点进行移动,当arr[l] <= 分界点时,继续移动,直到arr[l] > 分界点;同理,当arr[r] >= 分界点时,继续移动,直到arr[r] < 分界点。然后我们再交换arr[l],arr[r]的值,这样就可以调整区间了。
代码
c++
void quickSort(int a[], int l, int r){
//如果数组中就一个数,就已经排好了,直接返回。
if(l >= r) return;
//选取分界线。这里选数组中间那个数
int x = a[l + r >> 1];
int i = l - 1, j = r + 1;
//划分成左右两个部分
while(i < j){
while(a[++i] < x);
while(a[--j] > x);
if(i < j){
swap(a[i], a[j]);
}
}
//对左部分排序
quickSort(a, l, j);
//对右部分排序
quickSort(a, j + 1, r);
}
javascript
const quickSort = (arr,l,r) => {
if(l >= r) return;
let i = l - 1, j = r + 1;
// 取分界点
let mid = arr[l + r >> 1];
while(i < j) {
while(arr[++i] < mid);
while(arr[--j] > mid);
if(i < j) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
quickSort(arr,l ,j );
quickSort(arr,j + 1, r);
}
时间复杂度
最好情况:O(nlong)
最坏情况:O(n^2)
平均时间复杂度:O(nlogn)
归并排序
归并排序的基本思想也是分治。快排的分界点是一个数,而归并排序是使用中间点来分的
- 确定分界点mid = (l + r) >> 1
- 递归排序left,right
- 合并两个排好序的数组
代码
c++
void merge_sort(int q[], int l, int r)
{
if (l >= r) return; //如果区间个数是1个或者没有,return
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);//递归排左边和右边
int k = 0, i = l, j = mid + 1;//k表示tmp里面数的个数(两个序列合并了几个数)i是左半边的起点,j是右半边的起点
while(i <= mid && j <= r) //i<=左半边边界,j<=右半边边界
{
if(q[i] <= q[j]) tmp[k ++] = q[i ++];//答案把q[i]拿过来
else tmp[k ++] = q[j ++];
}
while(i <= mid) tmp[k ++] = q[i ++];//把剩下的加上
while(j <= r) tmp[k ++] = q[j ++];
for(i = l, j = 0; i <= r; i ++, j ++) q[i] = tmp[j];//把存在tmp的结果复制到q里面
}
javascript
function merge(arr,l,r) {
if(l >= r) return;
const mid = l + r >> 1;
merge(arr,l,mid);
merge(arr, mid + 1, r)
let i = l, j = mid + 1, k = 0, tmp = [];
while(i <= mid && j <= r) {
if(arr[i] <= arr[j]) {
tmp[k++] = arr[i++];
}else {
tmp[k++] = arr[j++]
}
}
while(i <= mid) {
tmp[k++] = arr[i++];
}
while(j <= r) {
tmp[k++] = arr[j++];
}
for(let i = 0; i < tmp.length; i++) {
arr[l++] = tmp[i];
}
}
时间复杂度
最好情况:O(nlong)
最坏情况:O(nlong)
平均时间复杂度:O(nlogn)