一、冒泡排序:
两个相邻元素之间,两两进行相互比较,若前一个数比后一个数大,则交换位置。每经过一次循环,则都把较大的一个数放在后面。若有n个数需要排序,则需要两两比较n-1次。代码实现:
package cn.itcats.sort;
/**
* Java排序之 冒泡排序
*/
import org.junit.Test;
public class BubbleSort {
public void bubbleSort(int [] arr) {
//如果arr没有元素或只有一个元素
if(arr == null || arr.length < 2) {
return;
}
//外层循环代表比较的次数(比较arr.length个数,则循环arr.length-1次)
for(int i = 0 ;i < arr.length -1 ;i ++) {
//元素的下标
for(int j = 0 ;j <arr.length - 1 ;j ++) {
//前一个数比后一个数大
if(arr[j] > arr [j+1]) {
//交换位置
swap(arr,j,j+1);
}
}
}
}
//交换位置方法
private void swap(int[] arr, int j, int i) {
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
冒泡排序时间复杂度为:O(n²) ,额外时间复杂度 O(1)
第一次for循环(N) 第二次(N-1) 第三次(N-2)...是等差数列 An² + Bn +c (只要高阶项,不要低阶项,也不要高阶项的系数)则为n²。
二、选择排序:(记录最小值的下标)
如:一个数组中,arr[0]~arr[n-1]范围内找一个最小的数放在arr[0]位置,arr[1]~arr[n-1]范围内找一个最小的数再放arr[1]位置,arr[2]~arr[n-1]范围内找一个最小的数再放arr[2]位置......备注:n为arr.length数组长度。看代码:
package cn.itcats.sort;
import org.junit.Test;
/**
* Java排序之选择排序
*
* @author fatah
*/
public class SelectionSort {
public void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
// arr.length个数,每次都得到一个最小的数放在前面,需要比较arr.length -1次,
for (int i = 0; i < arr.length - 1; i++) {
//假设每次循环开始,arr[i]最小
int minIndex = i;
//最开始状态arr[0]和arr[0+1]比较,arr[1]和arr[1+1]比较
for (int j = i + 1; j < arr.length; j++) {
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
if(minIndex != i) {
swap(arr,i,minIndex);
}
}
}
private void swap(int[] arr, int i, int minIndex) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
选择排序复杂度也是O(n²)
三、插入排序
对于前两个冒泡排序和选择排序,基本不会出现在生产环境中,适合入门教学,而接下来讲的插入排序,则在生产环境中比较常见,举个例子介绍一下什么是插入排序:
我们应该都玩过扑克牌,从A-K,我们抓牌后都会把牌按从小到大排序。现在,我手中的牌都是按顺序排好的,我现在摸一张牌,比如是8,那么我就应该把它放到7和9之间。这就是插入排序,映射在JAVA代码中就是将8这张牌从大到小进行比较,进而进行移动,则当移动到8位置,把牌放入。此时停!!!不需要再往7~1之间比较遍历,因为其他顺序都是排好的。
package cn.itcats.sort;
import org.junit.Test;
public class InsertSort {
public void insertSort(int [] arr) {
if(arr == null || arr.length <2) {
return ;
}
//从第2个数开始比,即下标为[1]开始和前面数比
for(int i = 1; i < arr.length ; i++) { //最终执行到[arr.length-1]即arr最后一个元素
/**
* j为i前面的数,初始是i前面一个数
* 需要满足才发生插入:
* 1、j>=0
* 2、arr[j] (前面的数) > arr[j+1] (后面的数)
*/
for(int j = i -1 ; j >= 0 && arr[j] > arr[j+1] ; j--) {
swap(arr,j,j+1);
}
}
}
private void swap(int[] arr, int i, int j) {
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
}
四、归并排序
基于递归实现,首先,把集合或数组递归分为左右两个子序列(即无序向量的递归分解),系统递并各个子序列为有序向量。左右部分排好序,再用外排方式排序。
package cn.itcats.recursion;
import java.util.Arrays;
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int l, int r) {
if (l == r) {
return;
}
int mid = l + ((r - l) >> 1);
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
public static void merge(int[] arr, int l, int m, int r) {
int[] help = new int[r - l + 1];
int i = 0;
int p1 = l;
int p2 = m + 1;
while (p1 <= m && p2 <= r) {
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= r) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[l + i] = help[i];
}
}
}
O(N) = 2T(N/2)*(N) a=2,b=2,d=1 由master公式 :
log(b,a) = d -> 复杂度为O(N^d * logN)
时间复杂度O(N*logN),额外空间复杂度O(N)