一.选择排序
1.基本原理
假设要按升序排列一个数列。选择排序法先找到数列中最小的数,然后将它和第一个元素交换。接下来,在剩下的数中找到最小数,将它和第二个元素交换,依此类推,直到数列中仅剩一个数为止。
2.排序过程
以数组{49,38,65,97,76,13,27,49}为例:
第一次 : [13, 38, 65, 97, 76, 49, 27, 49]
第二次 : [13, 27, 65, 97, 76, 49, 38, 49]
第三次 : [13, 27, 38, 97, 76, 49, 65, 49]
第四次 : [13, 27, 38, 49, 76, 97, 65, 49]
第五次 : [13, 27, 38, 49, 49, 97, 65, 76]
第六次 : [13, 27, 38, 49, 49, 65, 97, 76]
第七次 : [13, 27, 38, 49, 49, 65, 76, 97]
3.复杂程度
选择排序的时间复杂度为 O(n^2)。
第一次需要检查n个元素,但随后检查的元素数依次为n - 1, n – 2, …, 2和1。平均每次检查的元素数为1/2 * n, 因此运行时间为 n * 1/2 * n,简单地写作 O(n^2)。
4.JAVA实现如下:
class selectSort{
public static void main(String[]args){
int[] arr={49,38,65,97,76,13,27,49};
for(int i=0;i<arr.length-1;i++){ //-1是因为没有必要进行最后一个数
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
swap(arr,i,j);//即用即释放
}
}
}
show(arr);
}
public static void swap(int []arr,int i,int j ){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void show(int[]arr){
String s="[";
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
s+=arr[i]+"]";
}else{
s+=arr[i]+",";
}
}
System.out.println(s);
}
}
输出结果:
[13, 27, 38, 49, 49, 65, 76, 97]
二.冒泡排序
1.基本原理:
对比相邻的元素值,如果满足前一个元素值小于后一个元素值就交换元素值,把较小的元素移动到数组的前面(从小到大排序),把大的元素移动到数组的后面,即交换两个元素的位置,这样较小的元素就像气泡一样一直从底部上升到顶部。
2.排序过程
以数组[5,2,4,6,1,3]为例:
第一次:[2,4,5,1,3,6]
第二次:[2,4,1,3,5,6]
第三次:[2,1,3,4,5,6]
第四次:[1,2,3,4,5,6]
3.算法的实现
冒泡算法由双层循环实现,其中外层循环用于控制排序轮数,一般为要排序的数组长度减1,因为最后一次循环只剩下一个数组元素,不需要对比,同时已经完成排序了。内层循环主要是用于对比数组中每个邻近元素的大小,以确定是否交换位置,对比和交换的次数随排序轮数而减少。
4.JAVA实现如下:
class bubbleSort{
public static void main(String[]args){
int[] arr={5,2,4,6,1,3};
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
swap(arr,j,j+1);
}
}
}
show(arr);
}
public static void swap(int[]arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void show(int [] arr){
String s="[";
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
s+=arr[i]+"]";
}else{
s+=arr[i]+",";
}
}
System.out.println(s);
}
}
输出结果:
[1,2,3,4,5,6]
三.插入排序
1.用一个插入排序的例子说明一下:[6,4,7,5]
使用6, 4, 7,5讲解插入排序的例子:
首先就是第一次插入排序,首先找到第一个数据6,因为此时6前面什么也没有,所以此时就不会进行插入排序,所以第一次的结果是6,4,7,5
然后就是第二次插入排序,此时的数据的顺序是6,4,7,5,然后就是开始第二个数据4,然后就把4这个数据和前面已经排好的顺序进行比较,此时的排好的数据就是6,所以此时就是6和4进行比较,因为4小于6,所以此时就会把4就会跑到6的前面,所以此时的结果就是4,6,7,5
然后就是第三个数据7,此时的数据的顺序已经变成了4,6,7,5,然后就会把7和前面已经排好的顺序进行比较,此时的排好的数据就是4,6,首先是7和6比(为什么7和6先比呢,因为此时如果7和6比大的话,那么就不需要在和6前面的4比较了,因为4和6是已经排序好了的),然后比较之后发现7比6大,所以此时就不需要变了,所以此时的结果就是4,6,7,5
然后就是第四个数据5,此时的数据的顺序已经变成了4,6,7,5,然后就会把5和已经排好的数据4,6,7进行比较,首先是5和7比(为什么5和7先比呢,因为此时如果5和7比大的话,那么就不需要和前面的6和4比较了,因为4,6,7是已经排序好了的),然后5和7比较之后,因为5比7小,所以此时顺序就是4,6,5,7,然后就是5和6比较,因为5比6小,所以此时顺序就是4,5,6,7,然后就是5和4比较,因为5比4大,所以顺序为 4,5,6,7
2.JAVA实现如下:
class insertSort{
public static void main(String[]args){
int [] arr={6,4,7,5};
int e;
int j;
for(int i=1;i<arr.length;i++){
e=arr[i];
for(j=i;j>0&&arr[j-1]>e;j--){ //指针j从第二位数开始即j>0
arr[j]=arr[j-1];
}
arr[j]=e;
}
show(arr);
}
public static void swap(int []arr,int i,int j ){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void show(int[]arr){
String s="[";
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
s+=arr[i]+"]";
}else{
s+=arr[i]+",";
}
}
System.out.println(s);
}
}
输出结果:
[4,5,6,7]
四.计数排序
1.基本原理
2.JAVA实现如下:
class countSort{
public static void main(String[]args){
int[] arr={8,5,9,2,7,4,6,1,3,10,-3,-2,-10};
int min=arr[0];
int max=arr[0];
for(int i=0;i<arr.length;i++){ //O(n)
if(arr[i]>max){
max=arr[i];
}
if(arr[i]<min){
min=arr[i];
}
}
int[] nums=new int[max-min+1];
int offset=min;
for(int i=0;i<arr.length;i++){ //O(n)
nums[arr[i]-offset]++;
}
int index=0;
for(int i=0;i<nums.length;i++){ //O(m)
if(nums[i]!=0){
for(int j=0;j<nums[i];j++){
arr[index++]=i+offset;
}
}
}
show(arr);
}
public static void swap(int []arr,int i,int j ){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void show(int[]arr){
String s="[";
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
s+=arr[i]+"]";
}else{
s+=arr[i]+",";
}
}
System.out.println(s);
}
}
输出结果:
[-10,-3,-2,1,2,3,4,5,6,7,8,9,10]
总结:
- 选择,冒泡,插入三个排序都是根据数据之间的大小关系进行比较排序的
- 计数 基数 桶 都是根据数据本身的特性比较 与大小无关的排序,这些排序只针对整数
- 是一个典型的牺牲空间换时间的排序