排序是很常见,其实一般竞赛是直接用sort就好了, 但是有时候我们会遇到一些题目, 他需要一些排序算法的思想,so today i 写一篇;
1. 冒泡排序
最最简但的排序, 优点是好写,稳定, 缺点就是太慢,简单不赘述了。
#include <bits/stdc++.h>
using namespace std;
void bubblesort(int a[], int len){
for (int i = 0; i < len - 1; i ++){
for (int j = 0 ; j < len - i - 1; j ++){
if (a[j] > a[j + 1]){
swap(a[j], a[j + 1]);
}
}
}
}
int main (){
int a[] = {-1, -2, 0,7,-89,1000};
int len = sizeof(a) / sizeof(a[0]);
bubblesort(a, len);
for (int i = 0 ; i <= len - 1; i ++){
cout << a[i] << " ";
}
return 0;
}
2.选择排序
从i的右边找到一个比a[i]小的数跟a[i]交换位置, 以此类推 时间复杂度n^2
#include <bits/stdc++.h>
using namespace std;
void selection_sort(int a[], int len){
for (int i = 0; i < len - 1; i ++){
int temp = i;
for (int j = i + 1; j < len; j ++){
//cout << "a[" << j << "] = " << a[j] << " a[" << i << "] = " << a[i] << endl;
if (a[j] < a[temp]) {
temp = j;
//cout << "temp = " << temp << endl;
}
}
swap(a[temp], a[i]);
}
}
int main (){
int a[] = {4,3,2,1};
int len = sizeof(a)/sizeof(a[0]);
selection_sort(a, len);
for (int i = 0; i < sizeof(a)/ sizeof(a[0]); i ++){
cout << a[i] << " ";
}
return 0;
}
3. 插入排序
初始假设第一个数是有序的,then让下一个数在有序数组中通过冒泡排序找到自己的位置,直到整个数组都变成有序数组。例如{4, 2, -1, 0}; 默认4是有序的, 下一个数2应该放在有序数组{4}的左边{2, 4} 无序数组变为{-1, 0}, 接下来继续操作, 直至全部遍历一遍。
#include <bits/stdc++.h> // 插入排序;
using namespace std;
int a[] = {6, 1, 9, 2, 3, 7, 19, 15};
int main (){
for (int i = 1; i <= 7; i ++){ //7是数组大小
//第一层循环 i 指的是无序数组的第一个数
for (int j = i - 1; j >= 0; j --){
//有序数组的末尾数跟无序数组第一个相比 直到找到该无序数的位置
if (a[j] > a[j + 1]){ // 相当于在有序数组中运用冒泡排序找到位置
int temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
else break;
}
}
for (int i = 0; i <= 7; i ++){
cout << a[i] << " ";
}
return 0;
}
4,希尔排序
分组处理, 对每一组都进行插入排序
#include <bits/stdc++.h> //希尔排序
using namespace std;
// 易懂版本
int a[11] = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0, 14}; // 偶数奇数没有影响,下面会解释
int main (){
int d = 0, len = 11;
for (d = len / 2; d >= 1; d = d / 2) { //d表示分为多少组, 每个组内的相邻的数间隔是d
for (int i = 0; i < d; i ++){ // 将每一组都进行插入排序 0到d - 1 正好d个组, 所以i不能等于d
for (int j = i + d; j <= len - 1; j = j + d){ //无序数组的第一个数i+d
for (int k = j - d; k >= 0; k = k - d){
if (a[k] > a[k + d]){
int temp = a[k + d];
a[k + d] = a[k];
a[k] = temp;
}
else break;
}
}
}
}
for (int i = 0; i <= len - 1; i ++)cout << a[i] << " ";
return 0;
}
5. 归并排序;
归并排序是冯.诺伊曼提出的, 广泛的被应用, 运用了分治的思想,时间复杂度为nlogn, 空间复杂度为n,是一种简单高效的方法;
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int low, int mid, int hight){
int i = low, j = mid + 1, k = 0;
int *b = new int[hight - low + 1];
while (i <= mid && j <= hight){
if (a[i] >= a[j]){
b[k ++] = a[j ++];
}
else{
b[k ++] = a[i ++];
}
}
while (i <= mid){
b[k ++] = a[i ++];
}
while (j <= hight){
b[k ++] = a[j ++];
}
k = 0;
for (int i = low; i <= hight; i ++){
a[i] = b[k ++];
}
delete []b;
}
void mergesort(int a[], int low, int hight){
if (low < hight){
int mid = low + (hight - low) / 2;
mergesort(a, low, mid);
mergesort(a, mid + 1, hight);
merge(a, low, mid, hight);
}
}
int main (){
int n, a[100];
cin >> n;
for (int i = 0; i < n; i ++){
cin >> a[i];
}
mergesort(a, 0, n - 1);
for (int i = 0 ; i <= n - 1; i ++){
cout << a[i] << " ";
}
return 0;
}
例子:图片复制于http://t.csdn.cn/eoAnM
其中,mergesort函数就是在分, merge就是在治,也就是和并;
6. 快速排序
看这个名字就知道他有点东西,其实一般来说我们可以调用sort()函数,但是背后的源码还是要懂的,想细致的了解快排 可以看这个博客 http://t.csdn.cn/3QEkQ
// 快速排序
#include <bits/stdc++.h>
using namespace std;
void quicksort(int a[], int left, int right){
if (left > right) return ;
int temp = a[left];//最左边的数据作为基准;
int i = left, j = right;
while (i != j){
while (a[j] >= temp && j > i) j --;//如果后边的元素大于等于基准元素,就 j --;
if (j > i) a[i ++] = a[j]; // i == j时就不用换位置了;
while (a[i] < temp && i < j) i ++;
if (i < j) a[j --] = a[i];
}
a[i] = temp; //这里i 跟 j 相等, 用哪个都行 // 找到了基准元素的位置,其左面的元素全部小于它,右边的元素全部大于它,
//所以它的位置一定是正确的;
//接下来递归, 基准左面的所有元素 ,右边的所有元素;
quicksort(a, left, i - 1);
quicksort(a, i + 1, right);
}
int main (){
int a[] = {0, 37, 43, 1, -2, -2, 788, 0};
quicksort(a, 0, sizeof(a)/sizeof(a[0]) - 1);
for (int i = 0; i < sizeof(a)/sizeof(a[0]); i ++){
cout << a[i] << " ";
}
return 0;
}
(图片来自蓝桥云课);
快排, 给基准元素找位置,例如,图中的49我们就假设是基准元素,通过操作找到了它的位置再递归分治找一下个, 最后就是有序的,但是切记,快速排序是不稳定的,什么是不稳定排序呢,
就是例如, {0, 0, 0, 6, 1, 2}; 排序之后 {0 ,0 ,0,1, 2, 6}; 1, 2, 6没问题
但是0不一定, 因为三个0之间的绝对位置可能变了, 第三个0可能跑第一个去了,这个在算法竞赛中基本上用不到,了解就可以了,
7.堆排序
// 堆排序
#include <bits/stdc++.h>
using namespace std;
void max_heap(int a[], int start, int end){
int dad = start;
int son = dad * 2 + 1;
while (son <= end){
if (son + 1 <= end && a[son] < a[son + 1])
son ++;
if (a[dad] > a[son])
return ;
else {
swap(a[dad], a[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void adjust_heap(int a[], int len){
for (int i = len / 2 - 1; i >= 0; i --){
max_heap(a, i, len - 1);
}
for (int i = len - 1; i >= 0; i --){
swap(a[0], a[i]);
max_heap(a, 0, i - 1);
}
}
int main (){
int a[] = {57, 61, 97, 10, 28, 87, 9, 1, 1};
int len = sizeof(a) / sizeof(a[0]);
adjust_heap(a, len);
for (int i = 0; i < len; i ++){
cout << a[i] << " ";
}
cout << endl;
return 0;
}
8.计数排序
适用于数据量小且最大元素最小元素大小相差不大的排序;
小数不能用
#include <bits/stdc++.h>
using namespace std;
void count_sort(int a[], int len){
int Max = a[0], Min = a[0];
for (int i = 0; i < len; i ++){
Max = max(Max, a[i]);
Min = min(Min, a[i]);
}
int range = Max - Min + 1;
int *b = new int [range];
for (int i = 0; i < range; i ++){
b[i] = 0;
}
for (int i = 0; i < len; i ++){
b[a[i] - Min] ++;
}
cout << endl;
int cnt = 0;
for (int i = 0; i < range; i ++){
while (b[i] --){
a[cnt ++] = i + Min;
}
}
}
int main (){
int a[] = {0, 3, 5, -1, -5, 19, 8, 8};
int len = sizeof(a) / sizeof(a[0]);
count_sort(a, len);
for (int i = 0; i < len; i ++){
cout << a[i];
if (i != len - 1) cout << " ";
}
return 0;
}