排序
若待排序记录都在内存中,称为内部排序;
若待排序记录一部分在内存,一部分在外存,则称为外部排序。
冒泡排序(Bubble Sort)
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
这个算法的名字由来是因为越小/大的元素会经由交换慢慢"浮"到数列的顶端。
冒泡排序还有一种优化算法,就是立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来说并没有什么太大作用。
//排序结果为升序
#include<iostream>
using namespace std;
int a[100005];
//注释部分为优化
int main(){
int n; cin >> n;
for(int i = 0; i < n; i++)cin >> a[i];
for (int i = 0; i < n; ++i) {
//int mark = 0;
for (int j = 0; j < n; ++j) {
if(a[i] < a[j]){
swap(a[i], a[j]);
// mark = 1;
}
}
//if(!mark)break;
}
for(int i = 0; i < n; i++)cout << a[i] << " ";
return 0;
}
选择排序
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
//排序结果为降序
#include<iostream>
using namespace std;
int a[100005];
//注释部分为优化
int main(){
int n; cin >> n;
for(int i = 0; i < n; i++)cin >> a[i];
for (int i = 0; i < n; ++i) {
//int mark = 0;
for (int j = i+1; j < n; ++j) {//与冒泡排序不同的地方
if(a[i] < a[j]){
swap(a[i], a[j]);
// mark = 1;
}
}
//if(!mark)break;
}
for(int i = 0; i < n; i++)cout << a[i] << " ";
return 0;
}
快速排序
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下(顺序数列的快排)则需要 Ο(n2) 次比较。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
#include<bits/stdc++.h>
using namespace std;
int a[1000005];
void qs(int a[], int l, int r){
if(l >= r)return ;
int x = a[l+r>>1], 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]);
}
qs(a, l, j);
qs(a, j+1, r);
}
int main(){
int n; cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
qs(a, 0, n - 1);
for (int i = 0; i < n; ++i) {
cout << a[i] << " ";
}
return 0;
}
插入排序
#include<stdio.h>
void insert_sort(int a[], int len){
for(int i = 1; i < len; i++){
int now = a[i]; //新插入序列的值
int j = i-1;//当前已经有序的序列中的最后一位
while((j>=0)&&(a[j]>now)){ //找到值应该放的位置同时保证合法
a[j+1] = a[j];
j--;
}
a[j+1] = now;
}
}
int main(){
int n;
scanf("%d", &n);
int a[n];
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
insert_sort(a, n);
for (int i = 0; i < n; ++i) {
printf("%d\n", a[i]);
}
return 0;
}
归并排序
对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。归并排序的时间复杂度是稳定的O(nlogn),而快排一般会比O(nlogn)少一些。
#include<iostream>
using namespace std;
const int N = 1e6+10;
int a[N];
int tmp[N];
void merge_sort(int a[], int l, int r){
if(l == r)return;
int mid = l+r>>1;
merge_sort(a, l, mid), merge_sort(a, mid+1, r);
int k =0, i = l, j = mid+1;
while(i <= mid && j <= r){
if(a[i] <= a[j]) tmp[k++] = a[i++];//取等号则是稳定的排序
else tmp[k++] = a[j++];
}
while(i <= mid)tmp[k++] = a[i++];
while(j <= r)tmp[k++] = a[j++];
for(int i = l, j = 0; i <= r; i++, j++) a[i] = tmp[j];
}
int main(){
int n; 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] << " ";
}
return 0;
}
题目
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对
输入格式
第一行包含整数 n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1≤n≤100000,数列中的元素的取值范围 [1,10^9]
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
#define ll long long
int a[N];
int tmp[N];
ll merge_sort(int a[], int l, int r){
if(l >= r)return 0;
int mid = l+r >> 1;
ll res = merge_sort(a, l , mid) + merge_sort(a, mid+1, r); // 逆序对
int k = 0, i = l, j = mid+1;
while(i <= mid && j <= r)
if(a[i] <= a[j]) tmp[k++] = a[i++];
else {
tmp[k++] = a[j++];
res += mid - i + 1; //逆序对
}
while(i <= mid) tmp[k++] = a[i++];
while(j <= r) tmp[k++] = a[j++];
for(i = l, j = 0; i <= r; i++, j++)a[i] = tmp[j];
return res;
}
int main(){
int n; cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
cout << merge_sort(a, 0, n-1);
// for (int i = 0; i < n; ++i) {
// cout << a[i] << " ";
// }
return 0;
}

浙公网安备 33010602011771号