O(nlogn)排序算法

排序算法

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

注意:本文图文并茂

将提供以下图文链接供大家理解:
图文链接:
飞书图解链接🎉🎉🎉
密码:9531F#72

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. 堆排序

小根堆

#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(){
priority_queue<int, vector<int>, greater<int>> q;
const int N = 1e5;
for(int i = 0; i < N; i ++ ){
int x = rand();
push(x);
q.push(x);
}
for(int i = 0; i < N / 2; i ++ ){
if(peek() != q.top()){
printf("peel: %d, top: %d\n", peek(), q.top());
return 0;
}else{
q.pop();
pop();
}
}
cout << "end...\n";
return 0;
}

大根堆

#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(){
priority_queue<int, vector<int>> q;
const int N = 1e5;
for(int i = 0; i < N; i ++ ){
int x = rand();
push(x);
q.push(x);
}
for(int i = 0; i < N / 2; i ++ ){
if(peek() != q.top()){
printf("peel: %d, top: %d\n", peek(), q.top());
return 0;
}else{
q.pop();
pop();
}
}
cout << "end...\n";
return 0;
}

题目一

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 P1177 【模板】排序

#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×108

#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

本文作者:爱情丶眨眼而去

本文链接:https://www.cnblogs.com/zshsboke/p/17860786.html

版权声明:本作品采用©️CC BY-NC-SA 4.0许可协议进行许可。

posted @   爱情丶眨眼而去  阅读(43)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 赤伶 HITA
  2. 2 樱花树下的约定 (DJ-lucky小阳版) 旺仔小乔
  3. 3 踏雪 国风新语,Babystop_山竹
  4. 4 虞兮叹 闻人听書_
  5. 5 广寒宫 花沫
  6. 6 踏山河 七叔(叶泽浩)
  7. 7 破茧 张韶涵
  8. 8 下山 要不要买菜
  9. 9 红昭愿 音阙诗听
  10. 10 渡我不渡她 独孤
  11. 11 海草舞 陈冬霖
  12. 12 纸短情长 (女声版) 林玉冰
  13. 13 把梦照亮 赵小炮
  14. 14 沙漠骆驼 烟火兄弟
  15. 15 赢在江湖 姜鹏
  16. 16 孤勇者 杨宇峰
  17. 17 口是心非 张大帅
  18. 18 赐我 小时姑娘
  19. 19 囍(Chinese Wedding) 葛东琪
踏山河 - 七叔(叶泽浩)
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

踏山河 - 七叔(叶泽浩)

词 Lyrics:祝何

曲 Music:祝何

编曲 Arranger:祝何

吉他 Guitar:潘春宇

混音师 Mixing Engineer:唐瑜

Atmos 混音:刘三斤/苍白/31Studio

合声 Backing vocals:田跃君

制作人 Produced by:田跃君

监制 Executive producer:蒋雪儿 Snow.J/游文雅

音乐统筹 Music co ordination:林宝川

出品 Produced:青风音乐 X 造音行动

OP/SP:青风音乐Cheerful Music

【未经授权不得翻唱或使用】

秋风落日入长河 江南烟雨行舟

乱石穿空 卷起多少的烽火

万里山河都踏过 天下又入谁手

万里山河都踏过 天下又入谁手

分分合合 不过几十载春秋

我在 十面埋伏 四面楚歌的时候

我在 十面埋伏 四面楚歌的时候

把酒与苍天对酌

纵然一去不回 此战又如何

谁见 万箭齐发 星火漫天夜如昼

刀光剑影交错

而我枪出如龙 乾坤撼动 一啸破苍穹

长枪刺破云霞 放下一生牵挂

望着寒月如牙 孤身纵马 生死无话

风卷残骑裂甲 血染万里黄沙

成败笑谈之间 与青史留下

我在 十面埋伏 四面楚歌的时候

我在 十面埋伏 四面楚歌的时候

把酒与苍天对酌

纵然一去不回 此战又如何

谁见 万箭齐发 星火漫天夜如昼

刀光剑影交错

而我枪出如龙 乾坤撼动 一啸破苍穹

长枪刺破云霞 放下一生牵挂

望着寒月如牙 孤身纵马 生死无话

风卷残骑裂甲 血染万里黄沙

成败笑谈之间 与青史留下

长枪刺破云霞 放下一生牵挂

望着寒月如牙 孤身纵马 生死无话

风卷残骑裂甲 血染万里黄沙

笑谈间 谁能留下