1、交换排序
上篇介绍了选择排序,那么接下来给大家介绍比较排序中的交换排序,“交换”顾名思义就是两两比较后,当满足某种条件时,互换位置;该排序包括冒泡排序和快速排序。
2、冒泡排序
冒泡排序是一种相对简单的比较排序方法,通过相邻元素两两比较,当满足某种比较条件时,交换彼此位置,它的整个运行过程类似水中气泡从下往上,逐渐变大的过程,所以叫冒泡排序。
2.1 算法分析
1、 算法时间复杂度:O(N*2);
2、 算法空间复杂度:O(1);
3、 稳定排序;
2.2 算法步骤
1、 从无序列表中比较2邻元素。如果第一个比第二个大,就交换它们两个;
2、 对每一对相邻元素做同样的工作,直到最后一个元素为最大的数为止,并使得无序列表的长度length=length-1;
3、 持续每次对越来越少的元素重复上面的步骤,直到无序列表的长度length=1为止;
2.3 冒泡排序Java代码
/**
* 冒泡排序
* 算法复杂度O(N*2)
* @param a
*/
public static <T extends Comparable<? super T>> void bubbleSort(T[] a) {
//外层比较次数
for (int i = 0; i < a.length-1; i++) {
//两两交换位置
for (int j = 0; j < a.length-i-1; j++) {
if(a[j].compareTo(a[j+1])>0) {
swap(a,j,j+1);
}
}
}
}
3、快速排序
基于分治策略,以某种规则方式从序列中找到一个基准点(普遍以序列第一个元素为基准),将序列划分为两个子序列,其中基准点左边的子序列所有元素都小于等于基准点,基准点右边的子序列所有元素都大于基准点,然后对子序列继续递归调用以上思想,直到子序列的大小为零或一,也就是已经排序好了;
3.1 算法分析
1、 时间复杂度:最坏时间O(N*2),最好时间O(NlogN);平均时间O(NlogN);
2、 空间复杂度:O(logN),虽然还是使用原来的序列,但是递归需要消耗栈空间;
3、 不稳定排序;
3.2 算法步骤
1、 找出基准点pivot,包括以下三种方式:
- 以序列的第一个元素作为基准点(本实例采用的策略),对于预排的情况比较糟糕;
- 随机生成序列中的位置,作为基准点;
- 三数中值法(第一个元素,中间元素,最后一个元素取中间值作为基准点),是相对较好的基准点选择法;
2、 基于基准点,将序列划分为两个子序列,其中基准点左边的序列所有元素都小于等于基准点,而基准点右边的子序列所有元素都大于基准点;
3、 对子序列迭代调用以上步骤,直到序列元素为0或1为止;
3.3 图解
3.4 快速排序Java代码
/**
* 柯里化调用快速排序法,
* @param arr 需要排序的原始数组
* @return
*/
public static <T extends Comparable<? super T>> void quickSort(T[] arr) {
//调用快速排序法
quickSort(arr,0,arr.length-1);
}
/**
* 快速排序法,
* 算法的运行时间为O(n^2);
* @param arr 需要排序的原始数组
* @return
*/
private static <T extends Comparable<? super T>> void quickSort(T[] arr,int low,int high) {
if(low<high) {
//1、基于基准点,将序列分为左右两个子序列
int middle=getMiddle(arr,low,high);
//2、递归调用
//左侧
quickSort(arr,low,middle-1);
//右侧
quickSort(arr,middle+1,high);
}
}
/**
* 获取对分位置;
* 使得数组的对分位置左边永远小于等于对分位置,右边永远大于对分位置
* @param list
* @param low
* @param high
* @return
*/
private static <T extends Comparable<? super T>> int getMiddle(T[] arr,int low,int high) {
//1、基准点
T temp=arr[low];
//2、将序列分为两个子序列,其中基准点左边的子序列所有元素都小于等于基准点值,而基准点右边的子序列恰相反;
while(low<high) {
//2.1 从右往左遍历直到遇到小于等于基准点的位置;
while(low<high && arr[high].compareTo(temp)>=0) {
high--;
}
arr[low]=arr[high];
//2.2从左往右遍历直到遇到大于基准点的位置;
while(low<high&& arr[low].compareTo(temp)<0) {
low++;
}
arr[high]=arr[low];
}
arr[low]=temp;
//3、返回基准点位置
return low;
}
4、简单测试
package xw.zx.algorithm.sort;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SortTest {
private static final int ARRAY_LEN=40;
private static Integer[] arr=new Integer[ARRAY_LEN];
public static void main(String[] args) {
List<Integer> l=new ArrayList<>();
for (int i = 0; i < ARRAY_LEN; i++) {
l.add(i+1);
}
//乱序列表
Collections.shuffle(l);
//列表转换成数组
arr=l.toArray(new Integer[0]);
System.out.println("输出原数组");
printVal(arr);
//冒泡、快速排序
//AllSorts.bubbleSort(arr);
AllSorts.quickSort(arr);
System.out.println("输出排序后的数组");
printVal(arr);
}
/**
* 打印数组
* @param arr
*/
private static void printVal(Integer[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println("");
}
}