章节构成:
桶排序(伪)
例:
题目:
将一堆数排序,给了范围0~10,设一个数组a[11],下标表示数,值表示该数出现几次,初始情况如图所示:
每个数出现一次,该数组值就 +1。
代码:
#include<iostream>
using namespace std;
int main()
{
int a[11],i,j,t;
for(i=0;i<=10;i++){
a[i]=0;//初始化为0
}
for(i=0;i<5;i++){//循环读入5个数
cin>>t;
a[t]++;
}
for(i=0;i<=10;i++){
for(j=1;j<=a[i];j++){
cout<<i<<" "; //出现几次,打印机次!!
}
}
return 0;
}
这种排序方法是一种简化的桶排序,真正的桶排序要比这个复杂。
注意
-
理解起来就是,把取值范围内的每个数看成一个"桶",输入的数放在与它对应的"桶"里,在按顺序遍历这些"桶",一次将桶清理干净
-
时间复杂度:O(M+N),但十分浪费空间!
-
当前的简化版不是一个真正意义上的排序算法,它仅仅排序了分数,但是这分数是谁的最后全乱了!!
冒泡排序
基本思想
每次比较两个相邻元素,如果顺序错误,就交换。
例:
题目:
12,35,99,18,76从大到小排?
排列过程:
- 1235991876(1,2位比较)
- 3512991876(2,3位比较)
- 3599121876(3,4位比较)
- 3599181276(4,5位比较)
- 3599187612(第一趟比较完~)
直至第4趟,是比较第1个与第2个数,完成后就剩第1个数,也就只能放在第1位了~~
总结:
- 有n个数进行排序,需进行n-1趟操作
- 每一趟从第1位开始,进行相邻两数比较,比较完成后向后挪移为继续比较
- 重复上1步骤,直至最后一个尚未归为的数
- 已经归位的数无需再比较~~
代码实现:
#include<iostream>
using namespace std;
int main()
{
int a[100],i,j,t,n;
cin>>n;
for(i=0;i<n;i++){
cin>>a[i];
}
//核心部分:
for(i=0;i<n-1;i++){//n个数排序,进行n-1趟!!
for(j=0;j<n-i-1;j++){//从第一位数开始,直到最后一个尚未归位的数
if(a[j] < a[j+1]){//从大到小~~
t=a[j];a[j]=a[j+1];a[j+1]=t;
}
}
}
for(i=0;i<n;i++){
printf("%d ",a[i]);
}
return 0;
}
注意
- 核心:双重嵌套循环~
- 时间复杂度:O(N2),复杂度非常高
快速排序
优点
快速排序解决了桶排序浪费空间和冒泡排序浪费时间的问题,
原理
- 在需要排序的数中找一个数为基准数(一般以第一个数位基准数),目标是通过移动数列中的其他数,将这个基准数,置于序列中间的某个位置,使左边的数比它小,右边的数比他大(如果是从小到大排),不断更新基准数,多轮重复,直到所有的数都归位为止。
- 他是基于"二分"的思想,每次交换都是跳跃式的,不会像冒泡一样只在相邻的数之间交换,交换的距离大了,交换的次数小了,速度就高了。
- 注意他的最差时间复杂度与冒泡一样为O(N2),而平均时间复杂度为O(NlogN)。
例:
题目:
将 6,1,2,7,9,3,4,5,10,8 从小到大排列?
方法:
- 设i,j为哨兵,分别从两端进行探测,先从右往左(j–)找一个小于6的数,再从左往右(i++)找一个大于6的数,然后交换数值。每次都是j先出发,直到i与j相遇,将基准数与相遇位置的数进行对调。这时"第一轮探测"结束。
- 当前以6位分界点分成了两个序列,左边为:3,1,2,5,4,右边为:9,7,10,8。这时按照之前的方法先处理左边的,直到左边全排好了,也就是成了1,2,3,4,5,再去管右边。
- 再次注意:每次都是"j哨兵"先动,原因是:最后和基准数交换的是比它小的,而j的职责就是找比基准数小的数,最后由i去碰j,或者是j最后碰到i了,此时的i还停留在上一次运行,所以他脚底下的数是经过上一次交换过来的比基准数小的数。
过程图解:
代码:
#include<iostream>
using namespace std;
int a[101],n;
void quicksort(int left,int right){
int i,j,t,temp;
if(left > right){//递归结束条件
return ;
}
temp=a[left];//temp中存的是基准数
i=left;
j=right;
while(i != j){
//顺序很重要!!先从右往左!!
while(a[j]>=temp && i<j){
j--;
}
//再从左往右
while(a[i]<=temp && i<j){
i++;
}
//交换两个数位置
if(i<j){//确定当i,j没有碰面!
t=a[i];a[i]=a[j];a[j]=t;
}
}
//最终将基准数归位!!
a[left]=a[i];
a[i]=temp;
quicksort(left,j-1);//继续处理左边的,递归
quicksort(i+1,right);//继续处理右边的,递归
}
int main()
{
int i,j,t;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
}
quicksort(1,n);//快速排序调用!
for(i=1;i<=n;i++){
printf("%d ",a[i]);
}
return 0;
}
/* 测试数据:
10
6 1 2 7 9 3 4 5 10 8
*/