排序

若待排序记录都在内存中,称为内部排序;

若待排序记录一部分在内存,一部分在外存,则称为外部排序。


冒泡排序(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;
}

posted @ 2022-07-16 16:53  每日一题,医生远离  阅读(63)  评论(0)    收藏  举报