/* O(nlogn)的排序 */
归并:非递归
使左有序,右有序
最后tmp数组,找左右区间较小值拷贝进去,再把剩余链接起来
复杂度:使左有序,右有序 O(n) cnt:logn
all:O(nlogn)
归并:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N], tmp[N];
int n;
void merge(int v[], int l, int mid, int r){
int p1 = l, p2 = mid+1;
int i = l;
while(p1 <= mid && p2 <= r) {
if(v[p1] <= v[p2]) tmp[i++] = v[p1 ++ ];
else tmp[i++] = v[p2++];
}
while(p1 <= mid) tmp[i++] = v[p1 ++ ];
while(p2 <= r) tmp[i++] = v[p2 ++ ];
for (int i = l; i <= r; i ++ )
v[i] = tmp[i];
}
void merge_sort(int v[], int l, int r){
if(l >= r) return ;
int mid = l + r >> 1;
merge_sort(v, l, mid);
merge_sort(v, mid+1, r);
merge(v, l, mid, r);
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> a[i];
merge_sort(a, 0, n-1);
for (int i = 0; i < n; i ++ ) cout << a[i] << ' ';
}
小和:
相同时,先拷贝右
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int res = 0;
int a[N], tmp[N];
int n;
void merge(int v[], int l, int mid, int r) {
int p1 = l, p2 = mid + 1;
int i = l;
while(p1 <= mid && p2 <= r) {
if(v[p1] < v[p2]){
res += (r-p2+1) * v[p1] ; //找到右边比v[p1]大的
tmp[i++] = v[p1++];
}else
tmp[i++] = v[p2++];
}
while(p1 <= mid)
tmp[i++] = v[p1++];
while(p2 <= r)
tmp[i++] = v[p2++];
for (int i = l; i <= r; i ++ )
v[i] = tmp[i];
}
void merge_sort(int v[], int l, int r) {
if(l >= r) return;
int mid = l + r >> 1;
merge_sort(v, l, mid);
merge_sort(v, mid+1, r);
merge(v, l, mid, r);
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> a[i];
merge_sort(a, 0, n-1);
cout << res << endl;
}
逆序对:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int res = 0;
int a[N], tmp[N];
int n;
void merge(int v[], int l, int mid, int r) {
int p1 = l, p2 = mid + 1;
int i = l;
while(p1 <= mid && p2 <= r) {
if(v[p1] > v[p2]){
res += mid-p1+1 ; //找到右边比v[p1]大的
tmp[i++] = v[p2++];
}else
tmp[i++] = v[p1++];
}
while(p1 <= mid)
tmp[i++] = v[p1++];
while(p2 <= r)
tmp[i++] = v[p2++];
for (int i = l; i <= r; i ++ )
v[i] = tmp[i];
}
void merge_sort(int v[], int l, int r) {
if(l >= r) return;
int mid = l + r >> 1;
merge_sort(v, l, mid);
merge_sort(v, mid+1, r);
merge(v, l, mid, r);
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> a[i];
merge_sort(a, 0, n-1);
cout << res << endl;
}
<= | >
[i] <= num ,把[i]和<=区的下一个数交换,<=区右括,i ++
[i] > num,i ++
标记指针:左侧及指针都比给定num小
找到大的,继续走;找到小的,交换到标记指针,区域+1
荷兰国旗
< | = | >
[i] < num ,把[i]和<=区的下一个数交换,<=区右括,i ++
[i] > num,i ++
[i] > num ,把[i]和<=区的前一个数交换,>=区左括,i 原地不变(交换过来的数还未参与判断)
快排:
<= | >
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J9NJ8CP2-1679686290447)(pic/quick1.png)]
快排2 : 荷兰国旗 类似上
快排1、2:存在最坏的情况 O(n*n)
快排3:随机选择pivot O(nlogn)
//快排3c++
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
int q[N];
int p[2];
void swap(int q[], int x, int y) {
int tmp = q[x];
q[x] = q[y];
q[y] = tmp;
}
void partition(int arr[], int L, int R) {
int less = L - 1;
int more = R;
while(L < more) { //用L跑
if(arr[L] < arr[R]) { // 小
swap(arr, ++less, L++); // 区域+1
} else if(arr[L] > arr[R]) { //大
swap(arr, --more, L); //区域+1
} else { // 相等
L ++; //区域不变
}
}
swap(arr, more, R);
p[0] = less + 1, p[1] = more;
}
void quick_sort(int q[], int L, int R) {
if(L < R) {
swap(q, L+(int)(rand()%(R-L+1)), R); //随机选择一个pivot
partition(q, L, R); // q[0] - q[1]的位置是 == pivot的元素,q[0]左侧< q[1]右侧>
quick_sort(q, L, p[0]-1);
quick_sort(q, p[1] + 1, R);
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> q[i];
quick_sort(q, 0, n-1);
for (int i = 0; i < n; i ++ ) cout << q[i] << " ";
}