纯手打常见基础排序

冒泡排序

相邻的比较,复合条件就交换,需要走n-1趟
时间复杂度O(n^2)

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
//核心思想:
//相邻的两个比较,满足条件就交换
//从第一个元素开始,每结束一次循环就能确定一个最值
//所以需要循环n-1趟
int main(){
int n;
cin>>n;
int a[N];
for(int i=1;i<=n;i++)
cin>>a[i];
//核心开始了
//冒泡排序,只需要走n-1趟
for(int i=1;i<n;i++)
for(int j=1;j<=n-i;j++)
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}

选择排序

每次选出最小值放在前面
时间复杂度O(n^2)

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
//核心思想
//从第一个开始,每次选出后面最小值,然后交换
//
int main(){
int n;cin>>n;
int a[N];
for(int i=1;i<=n;i++)
cin>>a[i];
//正式开始
//核心思想: 遍历数组,每次选出最小的放在前面
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++){
int min=i;//记录最小值下标
if(a[min]>a[j])
min=j;
swap(a[i],a[min]);
}
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}

插入排序

时间复杂度O(n^2)

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
int main(){
int n;
cin>>n;
int a[N];
for(int i=1;i<=n;i++)
cin>>a[i];
//核心
for(int i=1;i<=n;i++){
int key=a[i];
int j=i-1;
while((j>=1)&&a[j]>key){
//后移
a[j+1]=a[j];
j--;
}
a[j+1]=key;
}
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}

快速排序

选出一个基数,大于基础的放右边,小于基数的放左边
快速排序的优点在于: 对于 规模大且无序 的数组具有非常高的效率
时间复杂度O(nlogn)

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
//核心思想
//选出一个基数,比基数大的放右边,小的放左边
void quick_sort(int a[],int l,int r){
//结束条件
if(l>=r)
return;
//在做循环的时候,要先自增,所以要先减1
int i=l-1,j=r+1,x=a[l+r>>1];
//循环结束之后,
//1~~j <=a[x]
// j+1~r >=a[x]
while(i<j){
do{
i++;
}while(a[i]<x);
do{
j--;
}while(a[j]>x);
if(i<j)
swap(a[i],a[j]);
}
//子问题
quick_sort(a,l,j);//左边
quick_sort(a,j+1,r);//右边
}
int main(){
int n;
cin>>n;
int a[N];
for(int i=1;i<=n;i++)
cin>>a[i];
//正式开始
quick_sort(a,1,n);
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}

归并排序

本质是: 两个有序数组的合并
时间复杂度 O(nlogn)

#include<bits/stdc++.h>
using namespace std;
//核心思想:
//两个有序数组的合并
//归并排序,时间复杂度是O(nlogn),但是需要额外的内存
const int N=100005;
int tmp[N];
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
//先划分为n个独立的子序列
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j])
tmp[k ++ ] = q[i ++ ];
else
tmp[k ++ ] = q[j ++ ];
while (i <= mid)
tmp[k ++ ] = q[i ++ ];
while (j <= r)
tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ )
q[i] = tmp[j];
}
int main(){
int n;
cin>>n;
int a[N];
for(int i=1;i<=n;i++)
cin>>a[i];
merge_sort(a,1,n);
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}

堆排序

堆的本质就是一个完全二叉树,只不过哦满足特殊的要求


1. 大顶堆: 每一个 父节点 >= 子节点
2. 小顶堆: 每一个父节点 <= 子节点


根据这一特性,可以使用堆的性质来对元素进行排序


时间复杂度O(nlogn)

步骤:
1.从a[n/2] 到a[1] ,不断调整,每个分支结点与其孩子的值,使其满足大顶堆的性质
2.堆排序:
(1) 头尾交换 堆的长度减1
(2) 把"新堆"调整为大顶堆
(3)循环以上两步,直到只剩下对顶元素

//堆排序时间复杂度 O(nlogn)
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int a[N];
void adjust_heap(int a[] , int i , int len){
// n/2就是父节点的坐标 , i * 2 就指向子节点
for( i = i * 2 ; i <= len ; i *= 2){
//此时i指向左孩子
if(i < len && a[i] < a[i+1])//右孩子大
i ++ ;
if(a[i] > a[i/2])//如果孩子 > 父节点,则交换
swap(a[i], a[i/2]);
else//父节点大于两个子节点,则不需要交换
break;
}
}
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i] ;
// 建 大顶堆, 必须从下向上 调整
// [n/2] 为最后一个分支结点(父节点)
for(int i = n/2;i >= 1; i--)
adjust_heap(a,i,n) ;
cout << endl;
//堆排序
// 堆顶 的元素 肯定是最大的,每次把堆顶的值放最后
for(int i = n; i >= 2; i--){
swap(a[1],a[i]);// 最大值已经到了最后
adjust_heap(a,1,i-1);//调整剩余n-1个
}
// 输出
for(int i = 1; i <= n; i++)
cout << a[i] << ' ';
}

我们常用的 priority_queue的底层实现就是堆,因此可以使用priority_queue来模拟堆排序,但是效率较数组模拟较差

posted @   秋天Code  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示