排序
一、sort函数
sort并不是简单的快速排序,它对普通的快速排序进行了优化,此外,它还结合了插入排序和推排序。系统会根据你的数据形式和数据量自动选择合适的排序方法,这并不是说它每次排序只选择一种方法,它是在一次完整排序中不同的情况选用不同方法,比如给一个数据量较大的数组排序,开始采用快速排序,分段递归,分段之后每一段的数据量达到一个较小值后它就不继续往下递归,而是选择插入排序,如果递归的太深,他会选择推排序。
时间复杂度:n*lg(n)
头文件:< algorithm >
形式:sort(first_pointer,first_pointer+n,cmp)
即sort(起始地址,结束地址,排序方式【less<数据类型>()——从小到大,greater<数据类型>()——从大到小】
如下,就是一个简单的把输入进行从小到大排序的例子:
#include <algorithm>
int main()
{
int m; //m个选票
cin >> m;
int* a = new int[m];
for (int i = 0; i < m; i++)
cin >> a[i];
sort(a, a + m, less<int>());
for (int i = 0; i < m; i++)
cout << a[i] << " ";
}
如果是结构体排序?不能用less和greater
采用下面这种【通用的】做法:
//情况一:数组排列
int A[100];
bool cmp1(int a,int b)//int为数组数据类型
{
return a>b;//降序排列
//return a<b;//默认的升序排列
}
sort(A,A+100,cmp1);
//情况二:结构体排序
Student Stu[100];
bool cmp2(Student a,Student b)
{
return a.id>b.id;//按照学号降序排列
//return a.id<b.id;//按照学号升序排列
}
sort(Stu,Stu+100,cmp2);
举一个题目的例子:
【先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。】
struct st
{
int num;
int c;
int m;
int e;
int sum;
};
//先按总分从高到低排序,
//如果两个同学总分相同,再按语文成绩从高到低排序,
//如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面
bool compare(st a,st b)
{
if (a.sum > b.sum)
return 1;
else if (a.sum < b.sum)
return 0;
else
{
if (a.c > b.c)
return 1;
else if(a.c < b.c)
return 0;
else if (a.c = b.c)
{
if (a.num < b.num)
return 1;
else
return 0;
}
}
}
//最后在main里调用
sort(a, a + n, compare);
除了以上,快速排序的原理如下代码:
#include<iostream>
using namespace std;
int n,a[1000001];
void qsort(int l,int r)//应用二分思想
{
int mid=a[(l+r)/2];//中间数
int i=l,j=r;
do{
while(a[i]<mid) i++;//查找左半部分比中间数大的数
while(a[j]>mid) j--;//查找右半部分比中间数小的数
if(i<=j)//如果有一组不满足排序条件(左小右大)的数
{
swap(a[i],a[j]);//交换
i++;
j--;
}
}while(i<=j);//这里注意要有=
if(l<j) qsort(l,j);//递归搜索左半部分
if(i<r) qsort(i,r);//递归搜索右半部分
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
qsort(1,n);
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
}
二、桶排
如果快排还TLE了,那就用桶排吧!
(转载)
桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来记得到有序序列。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是比较排序,他不受到O(n log n)下限的影响。
基本思想
桶排序的思想近乎彻底的分治思想。
桶排序假设待排序的一组数均匀独立的分布在一个范围中,并将这一范围划分成几个子范围(桶)。
然后基于某种映射函数f ,将待排序列的关键字 k 映射到第i个桶中 (即桶数组B 的下标i) ,那么该关键字k 就作为 B[i]中的元素 (每个桶B[i]都是一组大小为N/M 的序列 )。
接着将各个桶中的数据有序的合并起来 : 对每个桶B[i] 中的所有元素进行比较排序 (可以使用快排)。然后依次枚举输出 B[0]….B[M] 中的全部内容即是一个有序序列。
实现逻辑
- 设置一个定量的数组当作空桶子。
- 寻访序列,并且把项目一个一个放到对应的桶子去。
- 对每个不是空的桶子进行排序。
- 从不是空的桶子里把项目再放回原来的序列中。
时间复杂度
- 平均时间复杂度:O(n + k)
- 最佳时间复杂度:O(n + k)
- 最差时间复杂度:O(n ^ 2)
- 空间复杂度:O(n * k)
- 稳定性:稳定
如下列子(其实像计数排序?)
#include<bits/stdc++.h>
using namespace std;
int n,m; //m个数据(m<2000000),数据最大是n(n<1000)
int a[2000005],t[1000];//t为桶,a是要排序的大数列
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i];
++t[a[i]];//a[i]的出现次数+1
}
for(int i=1;i<=n;i++)//最大得数是n
{
for(int j=1;j<=t[i];j++)//这里循环输出,因为不要去充,所以要循环出现的次数次,输出i,如果没出现过,t【i】为0,直接跳过循环
cout<<i<<' ';
}
return 0;
}