首页 > 编程语言 >O(nlogn)排序算法

O(nlogn)排序算法

时间:2023-11-27 23:13:11浏览次数:40  
标签:02d 排序 int while 算法 tm time nlogn 节点

排序算法

介绍常见时间复杂度为\(O(nlogn)\)的排序算法

1. 快速排序

分治思想

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N];
void quick_sort(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]);
    }
    quick_sort(l, j), quick_sort(j + 1, r);
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    quick_sort(0, n - 1);
    for(int i = 0; i < n; i ++ ) printf("%d ", a[i]);
    return 0;
}

题目一

Luogu P1923 【深基9.例4】求第 k 小的数

#include<bits/stdc++.h>
using namespace std;
const int N = 5e6 + 10;
int a[N], n, k; // k代表索引
int quick_sort(int l, int r){
    if(l >= r) return a[l];
    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]);
    }
    if(k <= j) return quick_sort(l, j);
    return quick_sort(j + 1, r);
}
int main(){
    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    printf("%d", quick_sort(0, n - 1));
    return 0;
}

题目二

Luogu P1138 第 k 小整数

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int a[N], n, k, t, len; // k代表索引, t暂存数据, len表示a数组的长度
bool c[N]; // bool数组
int quick_sort(int l, int r){
    if(l >= r) return a[l];
    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]);
    }
    if(k <= j) return quick_sort(l, j);
    return quick_sort(j + 1, r);
}
int main(){
    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i ++ ){
        scanf("%d", &t);
        if(!c[t]){
            a[len ++ ] = t;
            c[t] = true;
        }
    }
    k -- ; // k代表索引
    k >= len ? puts("NO RESULT") : printf("%d", quick_sort(0, len - 1));
    return 0;
}

2. 归并排序

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
void merge_sort(int l, int r){
    if(l >= r) return;
    int mid = l + r >> 1;
    merge_sort(l, mid), merge_sort(mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while(i <= mid && j <= r){
        if(a[i] <= a[j]) b[k ++ ] = a[i ++ ]; // 保证稳定性
        else b[k ++ ] = a[j ++ ];
    }
    while(i <= mid) b[k ++ ] = a[i ++ ];
    while(j <= r) b[k ++ ] = a[j ++ ];
    for(i = l; i <= r; i ++ ) a[i] = b[i];
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    merge_sort(0, n - 1);
    for(int i = 0; i < n; i ++ ) printf("%d ", a[i]);
    return 0;
}

题目一

Luogu P1908 逆序对

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int a[N], b[N];
LL res;
void merge_sort(int l, int r){
    if(l >= r) return;
    int mid = l + r >> 1;
    merge_sort(l, mid), merge_sort(mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while(i <= mid && j <= r){
        if(a[i] <= a[j]) b[k ++ ] = a[i ++ ];
        else b[k ++ ] = a[j ++ ], res += mid - i + 1;  
    }
    while(i <= mid) b[k ++ ] = a[i ++ ];
    while(j <= r) b[k ++ ] = a[j ++ ];
    for(i = l; i <= r; i ++ ) a[i] = b[i];
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    merge_sort(0, n - 1);
    printf("%lld", res);
    return 0;
}

3. 堆排序

题目一

P3378 【模板】堆
解法1

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N], len;
void up(int i){
    // 如果父节点不为根节点,且父根节点的值大于子节点,则交换,递归此过程
    if(i / 2 && a[i / 2] > a[i]) swap(a[i], a[i / 2]), up(i / 2);
}
void push(int x){
    a[ ++ len] = x; // 压入x至数组结尾
    up(len); // 上移
}
void down(int i){
    int v = i;
    // 左子节点存在,且左子节点 < 父节点,父节点下移至左子节点
    if(i * 2 <= len && a[i * 2] < a[v]) v = i * 2;
    // 右子节点存在,且右子节点 < 父节点或者左子节点,父节点下移至右子节点
    if(i * 2 + 1 <= len && a[i * 2 + 1] < a[v]) v = i * 2 + 1;
    // 交互 父节点 和 左子节点或者右子节点
    if(i != v) swap(a[i], a[v]), down(v);
}
void pop(){
    a[1] = a[len -- ];
    down(1);
}
int peek(){
    return a[1];
}
int main(){
    int n, op, x;
    scanf("%d", &n);
    while(n -- ){
        scanf("%d", &op);
        if(op == 1){
            scanf("%d", &x);
            push(x);
        }else if(op == 2){
            printf("%d\n", peek());
        }else{
            pop();
        }
    }
    return 0;
}

解法2

#include<bits/stdc++.h>
using namespace std;
int main(){
    priority_queue<int, vector<int>, greater<int>> q;
    int n, op, x;
    scanf("%d", &n);
    while(n -- ){
        scanf("%d", &op);
        switch(op){
            case 1:
                scanf("%d", &x);
                q.push(x);
                break;
            case 2:
                printf("%d\n", q.top());
                break;
            case 3:
                q.pop();
                break;
        }
    }
    return 0;
}

题目二

Luogu P3378 【模板】堆

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N], len;
void up(int i){
    // 如果父节点不为根节点,且父根节点的值大于子节点,则交换,递归此过程
    if(i / 2 && a[i / 2] > a[i]) swap(a[i], a[i / 2]), up(i / 2);
}
void push(int x){
    a[ ++ len] = x; // 压入x至数组结尾
    up(len); // 上移
}
void down(int i){
    int v = i;
    // 左子节点存在,且左子节点 < 父节点,父节点下移至左子节点
    if(i * 2 <= len && a[i * 2] < a[v]) v = i * 2;
    // 右子节点存在,且右子节点 < 父节点或者左子节点,父节点下移至右子节点
    if(i * 2 + 1 <= len && a[i * 2 + 1] < a[v]) v = i * 2 + 1;
    // 交互 父节点 和 左子节点或者右子节点
    if(i != v) swap(a[i], a[v]), down(v);
}
void pop(){
    a[1] = a[len -- ];
    down(1);
}
int peek(){
    return a[1];
}
int main(){
    int n, x;
    scanf("%d", &n);
    for(int i = 0; i < n; i ++ ){
        scanf("%d", &x);
        push(x);
    }
    for(int i = 0; i < n; i ++ ){
        printf("%d ", peek()), pop();
    }
    return 0;
}

普通电子计算机1秒钟的算力大概是8亿也就是\(8 \times 10^8\)

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int cnt = 0;
    thread t([&](){
        while(true) cnt ++ ;
    });
    t.detach(); // 守护线程

    time_t nowtime;
    time(&nowtime);              // 获取1970年1月1日0点0分0秒到现在经过的秒数
    tm *p = localtime(&nowtime); // 将秒数转换为本地时间, 年从1900算起, 需要+1900, 月为0-11, 所以要+1
    printf("%04d:%02d:%02d %02d:%02d:%02d\n", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
    this_thread::sleep_for(chrono::seconds(1));
    time(&nowtime);    
    p = localtime(&nowtime);
    printf("%04d:%02d:%02d %02d:%02d:%02d\n", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
    printf("main: %d\n", cnt);
}

// Windows平台
#include <bits/stdc++.h>
#include <windows.h>
using namespace std;
int main()
{
    int cnt = 0;
    thread t([&](){
        while(true) cnt ++ ;
    });
    t.detach(); // 守护线程
    SYSTEMTIME time;
	GetLocalTime(&time);
	printf("%04d/%02d/%02d %02d:%02d:%02d:%03d\n", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds);
    this_thread::sleep_for(chrono::seconds(1));
    GetLocalTime(&time);
	printf("%04d/%02d/%02d %02d:%02d:%02d:%03d\n", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds);
    printf("main: %d\n", cnt);
    return 0;
}
// 789742137

思考: 堆排序为什么是不稳定的呢?

标签:02d,排序,int,while,算法,tm,time,nlogn,节点
From: https://www.cnblogs.com/zshsboke/p/17860786.html

相关文章

  • DFS算法的非递归遍历分析
    两种写法,一个是边表顶点号全部压栈,一个是类似后序非递归遍历1、voidDFS(GraphG,inti){intp,w;StackS;InitStack(S);Push(S,i);visited[i]=true;while(!isEmpty(S)){Pop(S,p);printf("%d",G.Ver[p].num);......
  • 数字在排序数组中出现的次数--二分
    题目描述有序序列二分先对左端点进行二分再对右端点二分最后得到两个端点,直接相减+1,得到区间个数classSolution{public:intgetNumberOfK(vector<int>&nums,intk){if(nums.empty())return0;intl=0,r=nums.size()-1;while(l<r......
  • 数组作为函数参数(冒泡排序)
    往往我们在导代码的时候,会将数组作为参数传个函数,比如我们要实现一个冒泡排序:函数讲一个整形数组进行排序(主要讲算法思想)#include<stdio.h>voidbubble_sort(intarr[],intsz){inti=0;//确认冒泡函数的趟数//intsz=sizeof(arr)/sizeof(arr[0]);//注:这里不能在void函......
  • 基于图像形态学处理和边缘提取算法的路面裂痕检测matlab仿真
    1.算法运行效果图预览   2.算法运行软件版本matlab2022a 3.算法理论概述       路面裂痕检测是基于图像处理和机器视觉的一种重要应用。通过图像形态学处理和边缘提取算法,我们可以有效地检测出路面的裂痕。路面裂痕检测主要基于图像处理和机器视觉的原理。......
  • 基于深度学习网络的烟雾检测算法matlab仿真
    1.算法运行效果图预览  2.算法运行软件版本matlab2022a 3.算法理论概述      基于深度学习网络的烟雾检测算法是一种端到端的检测方法,主要分为基于候选区域的二阶段目标检测器和基于回归的单阶段目标检测器两类。      基于候选区域的二阶段目标检测......
  • 前缀和算法总结
    前缀和思维导图:一维前缀和算法模版:1#include<iostream>23usingnamespacestd;45constintN=100010;67intn,m;8ints[N];910intmain()11{12scanf("%d%d",&n,&m);13for(inti=1;i<=n;i++)14......
  • Django - 多条queryset合并,并排序
     fromitertoolsimportchainfromoperatorimportattrgetter#拿到多条querysetqueryset1=model.objects.filter(status=1).all()queryset2=model.objects.filter(status=2).all()#将上面两组查询结果合并,并设置排序方式:-create_timenew_queryset=sorted......
  • 排序算法之冒泡排序优化1
    一:概述原始的数列{4,8,6,3,9,2,1,7},执行至第6步和第7步时,数列状态如下:很明显的可以看出,经过第6轮排序之后,整个数列已然是有序的了。可是排序算法依然是继续执行第7轮排序。在这种情况下,如果能判断出数列已经有序,并作出标记,那么剩下的几轮就不必执行了,可以提前结束。二:具体代码优化的......
  • 最小生成树(Kruskal和Prim算法)
    最小生成树(Kruskal和Prim算法)部分资料来源于:最小生成树(Kruskal算法)_kruskal算法求最小生成树-CSDN博客、【算法】最小生成树——Prim和Kruskal算法-CSDN博客关于图的几个概念定义:连通图:在无向图中,若任意两个顶点vi与vj都有路径相通,则称该无向图为连通图。强连通图:在有向图中,若......
  • Proj4:改进LiteOS中物理内存分配算法
    Proj4:改进LiteOS中物理内存分配算法实验目的掌握LiteOS系统调用的自定义方法实验环境Ubantu和IMX6ULLmini实验内容(从代码角度详细描述实验的步骤和过程)原先代码:1/*23*Description:findsuitablefreeblockuse"bestfit"algorithm45*Input......