总结:
我发现排序想要时间复杂度更低,要尽量保证排序的数组要规律有序,插入排序分为有序区和无序区,且无序要有序规律时会自动跳到下个无序,所以很快。
而根据“排序想要时间复杂度更低,要尽量保证排序的数组要规律有序”,可以将数组分成多个数组,排序后再合并排序,这就是归并排序,每次排序两个数组的内里相对有序的,所以会很快。
而桶排序也同理,是将数组的数根据值放到多个桶里,桶之间相对规律,将整体排序转化为多个桶的排序,将桶里的排序后再将桶合起来的到最终结果。
希尔排序也是同理,按倍数分成多个插排,而倍数位1时就是整体的插入排序,这个过程中每个倍数的插排都是在相对有序的数组上进行的,所以会更快,节省时间。所以当数据大的时候,希尔排序相对于插入排序优势更明显。
这些更快更高级的排序方法会抓住“想要时间复杂度更低,要尽量保证排序的数组要规律有序"的规律,所以基本上都用得到递归。
1.希尔排序
希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。
希尔排序实质上是一种分组插入方法。
希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。
//希尔排序
#include <iostream>
using namespace std;
void shell (int a[],int length,int n){
if(length!=0){
for(int i=1;i<=length;i++){
for(int j=0;j<n/length;j++){
for(int k=j-1;k>=0;k--){
if(a[i+k*length]<=a[i+(k+1)*length])break;
swap(a[i+k*length],a[i+(k+1)*length]);
}
}
}
shell(a,length/2,n);
}
}
int main ()
{
int n;cin >>n;
int a[n+1];
for(int i=1;i<=n;i++)cin >>a[i];
shell (a,n/2,n);
for(int i=1;i<=n;i++)cout <<a[i] << " ";
return 0;
}
2.计数排序
#include <iostream>
#include <vector>
using namespace std;
int main ()
{int n;cin >> n;
int a[n+1]={0};
int Max=0;
for(int i=1;i<=n;i++){
cin>>a[i];
Max=max(a[i],Max);}
vector<int> b(Max+1,0);
for(int i=1;i<=n;i++)b[a[i]]++;
for(int i=1;i<=Max;i++){
while(b[i]>0){
cout << i << " ";
b[i]--;
}
}
returns 0;
}
3.桶排序
计数排序的升级版,避免了多余空间的浪费,而且每个桶之间相对有序,对每个桶进行排序再整体整合
#include <iostream>
#include <vector>
using namespace std;
int n;
void tong(int Max,int Min,int a[]){
std :: vector< std ::vector<int> > vec((Max-Min+1)/10+1);
for(int i=1;i<=n;i++){
int index=(a[i]-Min+1)/10;
vec[index].push_back(a[i]);
}
for(int i=0;i<=(Max-Min+1)/10;i++){
for(int j=0;j<vec[i].size();j++){
for(int k=j-1;k>=0;k--){
if(vec[i][k]<=vec[i][k+1])break;
swap(vec[i][k],vec[i][k+1]);
}
}
}
for(int i=0;i<=(Max-Min+1)/10;i++){
for(int j=0;j<vec[i].size();j++){
cout <<vec[i][j] <<" ";
}
}
}
int main ()
{
cin >>n;
int a[n+1];
for(int i=1;i<=n;i++)cin >> a[i];
int Min=a[1],Max=a[1];
for(int i=1;i<=n;i++){
Min=min(a[i],Min);
Max=max(a[i],Max);
}
tong(Max,Min,a);
return 0;
}
4.堆排序
二叉树在数组中调用
#include <iostream>
using namespace std;
int jz[32]={1};
void zhuanhuan(int j,int a[],int er){
if(j*2<=er){
if(a[j]<a[j*2]&&a[j*2]>=a[j*2+1]){//j*2大
swap(a[j],a[j*2]);
zhuanhuan(j*2,a,er);
}
else
if(a[j]<a[j*2+1]&&a[j*2]<=a[j*2+1]){//j*2-1大
swap(a[j],a[j*2+1]);
zhuanhuan(j*2+1,a,er);
}
}
};
void duipai(int n,int a[],int shu,int er){
for(int i=shu-1;i>=0;i--){
for(int j=jz[i];j<=jz[i]*2-1;j++){
zhuanhuan(j,a,er);
}
}
}
int main()
{int n;cin >> n;
int shu=0;
int er=1;
while (er<n)
{er=er*2+1;
shu++;
jz[shu]=jz[shu-1]*2;
}
int a[er+1]={0};
for(int i=1;i<=n;i++)cin >> a[i];
for(int i=shu-1;i>=0;i--){
for(int j=jz[i];j<=jz[i]*2-1;j++){
zhuanhuan(j,a,er);
}
}
for(int i=1;i<=n;i++){
cout << a[1] << " ";
a[1]=0;
swap(a[1],a[n-1+1]);
zhuanhuan(1,a,er);
}
return 0;
}
5.归并排序
时间复杂度:O(n*logn)
将两个的有序数列合并成一个有序数列,我们称之为"归并"。
归并排序(Merge Sort)就是利用归并思想对数列进行排序,每次归并后归并得到的数列是有序的,对下一次归并的时间复杂度更有利(越规律越快)。
#include <iostream>
#include <vector>
using namespace std;
void digui(int a[],int start,int end){
if(start!=end){
digui(a,start,(start+end)/2);
digui(a,(start+end)/2+1,end);
vector<int> vec;
for(int j=(start+end)/2+1,i=start;j<=end||i<=(start+end)/2;j++){
while(a[j]>a[i]&&i<=(start+end)/2)
{
vec.push_back(a[i]);
i++;
}
vec.push_back(a[j]);
while(j==end&&i<=(start+end)/2){
vec.push_back(a[i]);
i++;
}
}
for(int i=start;i<=end;i++){
a[i]=vec[i-start];
}
}
}
int main()
{
int n;cin >> n;
int a[n+1]={0};
for(int i=1;i<=n;i++) cin >> a[i];
digui(a,1,n);
for(int i=1;i<=n;i++){
cout << a[i] << " ";
}
return 0;
}
6.快速排序
类似二分法查找,因为每个数最终排序后再数组中的位置是不变的,所以每次找数对应的位置使“在这之前小于它,在这之后大于它”,也是相对规律。缩短的排序的范围,每个数找到所在范围里的位置后,再分割,直到所有数排完为止。
通俗点就是用二分排序,每次排序后右边所有数大于左边,即是相对有序了,之后再进行快排(二分),直到排完。
#include <iostream>
using namespace std;
void kuaipai(int a[], int l, int r)
{
if (l < r)
{
int i,j,x;
i = l;
j = r;
x = a[i];
while (i < j)
{
while(i < j && a[j] > x)
j--; // 从右向左找第一个小于x的数
if(i < j)
a[i++] = a[j];
while(i < j && a[i] < x)
i++; // 从左向右找第一个大于x的数
if(i < j)
a[j--] = a[i];
}
a[i] = x;
kuaipai(a, l, i-1); /* 递归调用 */
kuaipai(a, i+1, r); /* 递归调用 */
}
}
int main ()
{int n; cin >> n;
int a[n+1];
for(int i=1;i<=n;i++)cin >> a[i];
kuaipai(a,1,n);
for(int i=1;i<=n;i++)cout << a[i] << " ";
return 0;
}