温故可以知新,排序算法不是很难,平时我们排序,java中都自带排序算法,像集合中自带的排序算法,底层实现就是归并排序和二叉树排序,有兴趣的小伙伴可以去看看。
下面聊聊普通的排序算法,不是特别深奥,直接写一点代码,回顾下算法的一些思想以及实现
1、冒泡排序,
这个就不说了,直接上代码了,最开始接触算法的时候学习的。
/**
* 冒泡排序
* 时间复杂度O(n*n)
* @param list
* @return
*/
public static List<Integer> sortByBob(List<Integer> list){
if(list.isEmpty()){
return new ArrayList<>();
}
int length = list.size();
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < length-1-i; j++) {
if(list.get(j)>list.get(j+1)){
int temp = list.get(j);
list.set(j,list.get(j+1));
list.set(j+1,temp);
}
}
}
System.out.println(JSONArray.toJSONString(list));
return list;
}
2、选择排序
选择排序,我感觉理解起来更简单,甚至我一直以为选择排序就是冒泡排序,因为是一个一个对比的,算法的复杂度也是O(n*n),这个大家了解下就好,一般很少用,太耗性能了,不划算的,来看下代码哈。
/**
* 选择排序,和冒泡排序时间复杂度一样,更容易理解
* 时间复杂度O(n*n)
* @param list
* @return
*/
public static List<Integer> sortByChoose(List<Integer> list){
if(list.isEmpty()){
return new ArrayList<>();
}
for (int i = 0; i < list.size(); i++) {
for (int j = i+1; j < list.size(); j++) {
if(list.get(i)>list.get(j)){
int temp = list.get(i);
list.set(i,list.get(j));
list.set(j,temp);
}
}
}
System.out.println(JSONArray.toJSONString(list));
return list;
}
3、插入排序
这个也是基础的排序,感觉是比冒泡排序消耗的性能少些,但是,最坏的情况下时间复杂度也是O(n*n),一般默认插入排序的时间复杂度就是O(n*n),这个大伙注意下哈,看下代码。
/**
* 插入排序
* 插入排序思想容易理解,写起来比较绕,就是把j位置上的值往前一位设置,判断当前的数据小于某一位时,停止复制,
* 把预存的i位置的值赋上去
* 这个感觉时间复杂度比冒泡少,但是实际上平均时间复杂度是n^2/4+n/2-1/2,最差的结果也是n^2
* @param list
* @return
*/
static public List<Integer> sortByInsert(List<Integer> list){
for (int i = 1; i < list.size(); i++) {
int j ;
if(list.get(i-1)>list.get(i)){
int temp = list.get(i);
for (j = i-1;j>=0&&temp<list.get(j);j--){
list.set(j+1,list.get(j));
}
list.set(j+1,temp);
}
}
System.out.println(JSONArray.toJSONString(list));
return list ;
}
4、快速排序
快速排序是一种分段递归的思想,时间复杂度是nlogN,是一种比较成熟的排序算法。好了,看下代码。
/**
* 快速排序
* (1)首先设定一个分界值,通过该分界值将数组分成左右两部分。 [2]
* (2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
* (3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
* (4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
* @return
*/
public static List<Integer> quickSort(List<Integer> list,Integer start,Integer end){
if (list.isEmpty()) return new ArrayList<>();
int i = start;
int j = end;
int mark = list.get(start);
while (i<j){
while ((i<j)&&list.get(j)>mark){
j--;
}
while ((i<j)&&(list.get(i)<mark)){
i++;
}
if((list.get(i)==list.get(j))&&i<j){
i++;
}else {
int temp = list.get(i);
list.set(i,list.get(j));
list.set(j,temp);
}
}
if(i-1>start) list = quickSort(list,start,i-1);
if(j+1<end) list = quickSort(list,j+1,end);
return list;
}
5、归并排序
这种排序算法应该说是比较接近我们的使用的,上面我也说了,集合排序中使用了归并排序,另外,MYSQL中的排序用的也是归并排序。归并排序是比较好理解的,效率也很高,不过比较耗费内存,但是这种消耗对于大多数系统来说都是可以接受的。看下代码。
/**
* 归并排序递归
* @param list
* @param left
* @param right
* @return
*/
public static List<Integer> mergeSort(List<Integer> list,int left,int right){
if(left<right){
int mid = (left+right)/2;
mergeSort(list,left,mid);
mergeSort(list,mid+1,right);
mergePlatfrom(list,left,mid,right);
}
return list;
}
/**
* 归并排序是底层实现
* @param list
* @param left
* @param mid
* @param right
*/
static public void mergePlatfrom(List<Integer> list,int left,int mid,int right){
List<Integer> temp = new ArrayList<>(); //存放排序后的新队列
int i = left;
int j = mid+1;
int t = 0;
while (i<=mid && j<=right){ //归并会从中间分开,从两侧依次拿出一个数据进行对比,然后放到新数据集合里面,这样新的数据集合里面的数据就是有序的
if(list.get(i)<=list.get(j)){
temp.add(list.get(i++));
} else {
temp.add(list.get(j++));
}
}
//表示左侧的数据很大,右侧的数据已经比完了,左侧还有多个数据,因为默认是有序的(会递归),所以直接放进新的数据集合里
while (i<=mid){
temp.add(list.get(i++));
}
//同理,表示右侧的数据很大,左侧的数据已经比完了,右侧还有多个数据,默认有序(会递归),也直接放进新的数据集合里
while (j<=right){
temp.add(list.get(j++));
}
//把排序后的新的数据集合放到原来的数据集合里面
t = 0;
while (left <= right){
list.set(left++,temp.get(t++));
}
}
代码写的不是特别经典,但还算简单易懂,实现了算法中主要的逻辑。想回顾下排序算法的小伙伴可以看下哈。
No sacrifice,no victory~