一、桶排序(记录数字出现的次数,出现几次打印几次)
输入样例
0 4 3 2 2
输出升序
0 2 2 3 4
输出降序
4 3 2 2 0
代码:
#include<stdio.h>
int main()
{
int tong[1001],i,j,num,n;
for(i=0;i<=1000;i++)
tong[i]=0;//初始化
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&num);
tong[num]++;//记录这个数字出现的次数,出现几次就打印几次
}
for(i=0;i<=1000;i++)//升序(最外层的for循环已经将数字默认排序了)
{
for(j=1;j<=tong[i];j++)
{
printf("%d ",i);
}
}
printf("\n");
for(i=1000;i>=0;i--)//降序
{
for(j=1;j<=tong[i];j++)
{
printf("%d ",i);
}
}
printf("\n");
return 0;
}
二、快速排序(分治思想)
输入样例
10
6 1 2 7 9 3 4 5 10 8
输出样例
1 2 3 4 5 6 7 8 9 10
代码一:
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;
int a[100010];
int n;
void quicksort(int l,int r)
{
int i=l,j=r;
int mid=a[(l+r)/2];//中间数,二分思想
while(i<=j)
{
while(a[i]<mid) i++;//查找左半部分比中间数大的数
while(a[j]>mid) j--;//查找右半部分比中间数小的数
if(i<=j)//如果不满足左小右大则交换
{
swap(a[i],a[j]);
i++;
j--;
}
}
if(l<j) quicksort(l,j);//递归搜索左半部分
if(i<r) quicksort(i,r);//递归搜索右半部分
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n);
for(i=1;i<=n-1;i++)
printf("%d ",a[i]);
printf("%d",a[n]);
return 0;
}
代码二:
#include<stdio.h>
int a[101],n;
void quicksort(int l,int r)//l:左边,r:右边
{
int i,j,t,base;
if(l>r) return;
base=a[l];//让最左边的为基准数
i=l,j=r;
while(i!=j)
{
while(a[j]>=base&&i<j)//先让j出发,j找到<=base的停止
j--;
while(a[i]<=base&&i<j)//i找到>=base的停止
i++;
if(i<j)//然后两者进行交换
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
a[l]=a[i];//最开始a[l]..a[i],ij相遇后交换,a[i]...a[l]
a[i]=base;//a[i]等于新的base
quicksort(l,i-1);//继续处理左边,递归过程 (0,i-1)
quicksort(i+1,r);//继续处理右边(i+1,n)
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n);
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
过程分析:
i | j |
6 (基数) | 1 | 2 | 7 | 4 | 3(j先) |
基数 | i | 交换 | j |
6 | 1 | 2 | 7 | 4 | 3 |
6 | 1 | 2 | 3 | 4 | 7 |
基数 | 交换 | j i相遇 |
6 | 1 | 2 | 3 | 4 | 7 |
4 | 1 | 2 | 3 | 6 | 7 |
新的基数 |
4 (i) | 1 | 2 | 3 | 6 | 7 |
4 | 1 | 2 | 3 | 6 |
6 | 7 |
i | 交换 | j i(相遇) | 6 |
4 | 1 | 2 | 3 | 6 | 7 |
3 | 1 | 2 | 4 | 6 | 7 |
基数 | ji相遇 |
3 | 1 | 2 | 4 |
2 | 1 | 3 | 4 |
基数 | ji相遇 |
2 | 1 | 3 | 4 |
1 | 2 | 3 | 4 |
最后顺序
1 | 2 | 3 | 4 | 6 | 7 |
代码三:
#include<iostream>
using namespace std;
const int N=1e6+10;
int n;
int q[N];
void quicksort(int q[],int l,int r)
{
if(l>=r) return;
int x=q[l],i=l-1,j=r+1;
while(i<j)
{
do i++;while(q[i]<x);//左边所有数<=x;
do j--;while(q[j]>x);//右边所有数>=x;
if(i<j) swap(q[i],q[j]);
//swap 交换
/*if(i<j)
{
int t=q[i];
q[i]=q[j];
q[j]=t;
} */
}
quick_sort(q,l,j);//递归排序左右两边
quick_sort(q,j+1,r);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&q[i]);
quicksort(q,0,n-1);
for(int i=0;i<n;i++)
printf("%d ",q[i]);
return 0;
}
方法:
确定分界点:左端:q[l] 中间:q[(l+r)/2] 右端:q[r]
调整区间 左边 :<=x 中间 x 右边:>=x
递归处理左右两端
三:归并排序(分治思想)
代码:
#include<iostream>
using namespace std;
const int N=1e6+10;
int q[N],temp[N];
int n;
void mergesort(int q[],int l,int r)
{
if(l>=r) return;
int mid=(l+r)>>1;//>>右移运算符,将一个二进制的数据右移一位
mergesort(q,l,mid),mergesort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(q[i]<=q[j]) temp[k++]=q[i++];
else temp[k++]=q[j++];
}
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
}
int main()
{
int n,i;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&q[i]);
mergesort(q,0,n-1);
for(i=0;i<n;i++)
printf("%d ",q[i]);
return 0;
}
方法:
确定分界点:mid=(l+r)/2;
递归排序两边
归并
ps:时间复杂度:
桶排序:O(N+M)
冒泡排序:O(N^2)
快速排序:O(NlongN)