在文章开始前,本文的代码主要参考了博客园中Bill Yuan的代码片段,加上自己的理解注释,如果有错误可以在评论中提出,只测试了小数据,当数据增大的时候,发现控制台无输出,debug调试发现排序功能正常,可能是因为数据太大需要的时间较长。
冒泡排序
冒泡排序是将数组中元素两两比较,如果前者比后者大,就将两者交换,实现将“轻的气泡浮上来”的过程。
public static void bubbleSort(int[] numbers){
int temp;
for(int i=0;i<numbers.length;i++)
//此层循环代表循环的次数,虽然看似当i时数组的最后一个数时不需要再多一次排序,但是判断条件如果为length-1会在数组长度为1的时候导致bug。
for(int j=i+1;j<numbers.length;j++){//此层循环代表一次从头到尾的排序
if(numbers[i]>numbers[j]){//如果前一个数大于后一个数,交换。
temp=numbers[i];
numbers[i]=numbers[j];
numbers[j]=temp;
}
}
在一次冒泡排序中,第一层遍历需要遍历n个元素,第二层遍历也需要遍历n个元素,所以冒泡排序的复杂度是O(n²)。
因为在排序过程中,当前一个元素和后一个元素相同时,两个元素不进行交换,所以冒泡算法是一个稳定的算法。
选择排序
选择排序的的工作原理是每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
public static void selectSort(int[] numbers){
int size=numbers.length,temp;
for(int i=0;i<size;i++){
int k=i;
for(int j=size-1;j>i;j--){
if(numbers[j]<numbers[k]) //从后往前找比number[i]小的数
k=j;
}
temp=numbers[i]; //找到比number[i]小的数后,
numbers[i]=numbers[k]; //交换number[i]和number[j]
numbers[k]=temp; //循环结束后,number[i]即是当前数组中最小的值
}
在一次选择排序中,第一层遍历需要遍历n个元素,第二层遍历也需要遍历n个元素,所以冒泡排序的复杂度是O(n²)。
因为在排序过程中,会存在如序列[5, 5, 3],第一次排序的时候前一个5已经到了后一个5的后方,所以选择排序是一个不稳定的算法。
插入排序
插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
public static void InsertSort(int[] numbers){
int size=numbers.length,temp,j;
for(int i=1;i<size;i++){ //不从0开始是因为numbers[0]要做第一个参照物
temp=numbers[i]; //先将numbers[i]保存在temp中
//如果numbers[j]比numbers[j-1]大 将numbers[i-1]的值赋给numbers[i],
//使用j的原因是要定位回原先i的位置,
//即此时在对第几个数排序
numbers[j]=numbers[j-1];
}
numbers[j]=temp;
//当numbers[i]比numbers[i-1]小时,此时number[i]的位置即是排好序的位置
}
在一次插入排序中,第一层遍历需要遍历n个元素,第二层遍历也需要遍历n个元素,所以冒泡排序的复杂度是O(n²)。
插入排序是从前往后取原序列的数,如果遇到相同的数则插在后面,所以不会产生交换,因此是一个稳定的算法。
快速排序
快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
public static void quickSort(int[] numbers,int start,int end){
if(start<end){
int base=numbers[start]; //设定基准数字
int temp; //用于交换的临时中间值
int i=start,j=end;
do{
while((numbers[j]>base)&&(j>start)) //从右往左找比基准小的数
j--;
while((numbers[i]<base)&&(i<end)) //从左往右找比基准大的数
i++;
if(i<=j){
temp=numbers[i]; //将i和j的数值交换
numbers[i]=numbers[j];
numbers[j]=temp;
i++;
j--;
/*System.out.println();
for(int x=0;x<numbers.length;x++){
System.out.print(numbers[x]+" ");
}*/
}
/*因为快排的方法是,先找基准(一般为第一个数),然后先从右往左找比基准小的数,
* 将基准和这个数交换,然后从左往右找比基准大的数,再次交换,直到两个数相同*/
}while(i<=j);
if(start<j)
quickSort(numbers,start,j);
if(end>i)
quickSort(numbers,i,end);
}
在一次快速排序中,因为使用的是分治的方法,每一次处理的数据量都是上一次的1/2,所以其复杂度是O(nlogn)。由于本人的高数确实学得不精,具体推导可以看下面这篇排序算法的文章。
由于在快速排序过程中,可能出现类似本来是第一个的5因为交换而到了第二个5后面的情况,所以快速排序是不稳定的算法。ex.53653第一次排序的时候,第一个5就到了最后的位置。