0x00-排序专题
冒泡排序
参考:https://zhuanlan.zhihu.com/p/126354159
冒泡排序(Bubble Sort) 最为简单的一种排序,通过重复走完数组的所有元素,通过打擂台的方式两个两个比较,直到没有数可以交换的时候结束这个数,再到下个数,直到整个数组排好顺序。因一个个浮出所以叫冒泡排序。双重循环时间 O(n^2)
算法描述:
-
比较相邻两个数据如果。第一个比第二个大,就交换两个数
-
对每一个相邻的数做同样1的工作,这样从开始一队到结尾一队在最后的数就是最大的数。
-
针对所有元素上面的操作,除了最后一个。
-
重复1~3步骤,知道顺序完成。
代码
//
// Created by majoe on 2020/8/19.
//
/**
* 输入:
* 5
* 2 3 4 5 1
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
int a[N];
//打印数组
void print(int *a, int len){
for (int i = 0; i < len; ++i) {
cout << a[i] << " ";
}
cout << endl;
}
/**
* 冒泡排序
* @param a 排序数组
* @param len 数组长度
*/
void bubbleSort(int *a,int len){
//经过len-1轮
for (int i = 0; i < len-1 ; ++i) {
//flag是否发生过交换
bool flag = false;
for (int j = 0; j < len-i-1 ; ++j) {
if(a[j] > a[j+1]) {
swap(a[j],a[j+1]);
flag = true;
}
}
//没有交换过,说明已经有序直接跳出
if(!flag) return;
}
}
int main(){
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
bubbleSort(a,n);
print(a,n);
return 0;
}
选择排序
选择排序(Select Sort) 是直观的排序,通过确定一个 Key 最大或最小值,再从带排序的的数中找出最大或最小的交换到对应位置。再选择次之。双重循环时间复杂度为 O(n^2)
算法描述:
- 在一个长度为 N 的无序数组中,第一次遍历 n-1 个数找到最小的和第一个数交换。
- 第二次从下一个数开始遍历 n-2 个数,找到最小的数和第二个数交换。
- 重复以上操作直到第 n-1 次遍历最小的数和第 n-1 个数交换,排序完成。
代码:
//
// Created by majoe on 2020/8/19.
//
/**
* 输入:
* 5
* 2 3 4 5 1
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
int a[N];
//打印数组
void print(int *a, int len){
for (int i = 0; i < len; ++i) {
cout << a[i] << " ";
}
cout << endl;
}
/**
* 选择排序
* @param a
* @param len
*/
void selectSort(int *a, int len){
int min;
//选择未排序数组最小的元素的下标,和未排序数组第一个元素交换
for (int i = 0; i < len-1; ++i) {
min = i;
for (int j = i+1; j < len ; ++j) {
//打擂台,找到最小值的下标
if(a[min] > a[j]) min = j;
}
swap(a[i],a[min]);
}
}
int main(){
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
selectSort(a,n);
print(a,n);
return 0;
}
快速排序
参考:https://www.zhihu.com/search?type=content&q=%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F
快速排序(QuickSort)是排除稳定性因素后最常用的排序。给看官介绍两种使用方法,一种值直接在我文件 stdlib.h 头文件中的 qsort 函数实现是和正常写代码一样的。通过使用qsort(数组名,长度,sizeof(第一个数长度),compInc/comoDec) 进行实现数组的排序。后面的是通过递归调用的形式。
算法描述:
//
// Created by majoe on 2020/8/19.
//
/**
* 输入:
* 5
* 2 3 4 5 1
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1000001;
int n;
int a[N];
void print(){
for (int i = 0; i < n; ++i) {
cout << a[i] << " ";
}
}
/**
* 快速排序
* @param st 左端点
* @param ed 右端点
*/
void qsort(int st, int ed){
if(st >= ed) return;
int mid = (st+ed)/2;
//swap(a[st],a[mid]);
int l = st,r= ed;
//基准值
int temp = a[l];
while (l < r){
while(l < r && temp <= a[r] ) r --;
a[l] = a[r];
while(l < r && temp >= a[l] ) l ++;
a[r] = a[l];
}
a[l] = temp;
qsort(st,l-1);
qsort(l+1,ed);
}
int main(){
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
qsort(0,n-1);
print();
return 0;
}
归并排序
归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
归并排序是用分治思想,分治模式在每一层递归上有三个步骤:
- 分解(Divide):将n个元素分成个含n/2个元素的子序列。
- 解决(Conquer):用合并排序法对两个子序列递归的排序。
- 合并(Combine):合并两个已排序的子序列已得到排序结果。
//
// Created by majoe on 2020/8/19.
//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
int a[N],b[N]; //a为原数组,b为备份数组
/**
* 归并排序
* @param a 数组
* @param l 左边界
* @param r 右边界
* @param b 额外的数组
*/
void msort(int l,int r){
if(l == r) return; //跳出条件
//切分操作
int mid = (l+r)>>1, i=l,j=mid+1;
msort(l,mid);
msort(j,r);
//合并操作,先放入备份数组里
for (int k = l; k <=r ; ++k) {
if(j>r || i<=mid && a[i]<=a[j]) b[k] = a[i++];
else b[k] = a[j++];
}
for(int k=l;k<=r;k++) a[k]=b[k];
}
void print(int *a, int len){
for (int i = 0; i < len; ++i) {
cout << a[i] << " ";
}
cout << endl;
}
int main(){
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
msort(0,n-1);
print(a,n);
return 0;
}