常见排序算法--简单排序
本文包括:
1.选择排序
2.冒泡排序/双向冒泡排序
3.插入排序
1.选择排序
选择排序是一种最为直观的排序方法。每次循环从数组中选择出一个最小或者最大的元素,按顺序重新放入数组中,直到所有的戴排序元素都排序完成。
public void selectSort(int[] a){ int temp=0; for(int i=0;i<a.length-1;i++){ for(int j=i+1;j<a.length;j++){ if(a[j]<a[i]){ temp = a[j]; a[j] = a[i]; a[i] = temp; } } } }
从代码不难看出,选择排序的过程是:第一次循环,遍历数组找出数组中最小的数字,放入a[0],第二次循环,找出剩下数组中最小的数字放入a[1]一次类推。
所以,选择排序的时间复杂度为O(n^2),如果n较大,则效率会非常低。
2.冒泡排序
冒泡排序也是较为简单的一种排序方法,之所以叫冒泡排序,是因为排序的手法会使数字浮到数组顶端而得名。
冒泡排序的手法是:比较相邻的两个元素,如果相邻的两个元素的顺序是错误的,则将他们交换;然后继续比较下一组相邻的元素。直到所有需要排列的元素都排序完成。
public void bubbSort(int[] a){ int temp=0; for(int i=0;i<a.length-1;i++){ for(int j=a.length-1;j>i;j--){ if(a[j]<a[j-1]){ temp = a[j]; a[j] = a[j-1]; a[j-1] = temp; } } } }
从代码我们可以看出来:冒泡排序是用层循环,外侧循环的意义是在于,循环n次,每次冒泡都冒出最小的节点依次放在数组的最前面。第二层循环的意义是在于,进行冒泡操作,每次比较相邻的两个元素,将较小的元素,像数组头方向移动。
因此我们可以看出冒泡排序的时间复杂度为O(n^2),如果n较大,则效率会非常低,如果数组是有序的,即进行一次冒泡扫描发现移动的关键次数为最小时,说明数组已经有序,此时的时间复杂度为O(n)。
双向冒泡排序:
传统的冒泡排序要么是从左向右进行,要么从右向左进行,每次都只对数组一头的元素进行扫描排序。
而双向冒泡排序首先从前往后把最大数移到最后,然后反过来从后往前把最小的一个数移动到数组最前面,这一过程就是第一轮,然后重复这一过程,最终就会把整个数组从小到大排列好。
public void bubbSort2(int[] a){ int left =1 ; int right = a.length -1; int t=0; while(left<=right){ for(int i=right;i>=left;i--){ if(a[i]<a[i-1]){ int temp; temp = a[i]; a[i] = a[i-1]; a[i-1] = temp; t = i;//记录上一次交换的下标 } } left = t+1; //t+1中间乱序部分的最左端 for(int i=left;i<right+1;i++){ if(a[i]<a[i-1]){ int temp; temp = a[i]; a[i] = a[i-1]; a[i-1] = temp; t = i;//记录上一次交换的下标 } } right = t-1;//t-1为中间乱序部分的最右端 } }
从代码看来,双向冒泡排序会比普通冒泡排序减少很多次循环。因为双向排序时数组的两头都排序好了,我们只需要处理数组的中间部分即可,普通冒泡排序只有一头的元素是排好序的。
虽然双向冒泡排序有些改进,但是不能大幅度的提升效率,这是由于冒泡排序的基本过程所确定的。
3.插入排序
插入排序的基本方法是,每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
public void insertSort(int[] a){ for(int i=1;i<a.length;i++){ int temp = a[i],j=i ; if(a[j-1]>temp){ while(j>=1&&a[j-1]>temp){//找到新元素合适的位置 a[j] = a[j-1];//前一个覆盖后一个 j--; } } a[j]=temp; //插入元素 } }
直接插入排序最好的时间复杂度为O(n),平均时间复杂度为O(n^2)。同样的,如果n过于大的时候,直接插入排序的效率会很低。
插入排序改进思路和冒泡排序一样,我们也可以对于直接插入排序进行改进。在直接插入排序中我们每次插入元素的时候,都是挨个遍历前面所有元素,这样遍历的效率并不高。
因为插入的数组是已经排好序的有序数组,所以我们自然而然的想到了折半插入的方法,这样可以减少比较的次数。
不过虽然折半插入会减少元素比较的次数,但因为是插入数组,所以,只是减少元素的比较次数,元素移动的个数依然没有改变,时间复杂度依然是O(n^2)。