1、冒泡排序
冒泡排序是知名排序方式,逻辑简单,实现起来也容易;
总的来说就是两层for循环,缺点就是时间复杂度较高。
一共进行n-1次循环,总比较次数:(n-1)+(n-2)+(n-3)……2+1=n*(n-1)/2,时间复杂度为O(n²)。
代码如下:
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {12, 45, 5677, 344, 56, 3, 546, 2435};
//冒泡排序
int[] bubbleSort = bubbleSort(arr);
System.out.println(Arrays.toString(bubbleSort));
}
/**
* 冒泡排序
*
* @param arr
*/
public static int[] bubbleSort(int[] arr) {
//i控制循环次数,长度为len的数组只需要循环len-1次,i的起始值为0所以i<len-1
for (int i = 0; i < arr.length - 1; i++) {
//但是由于是由arr[j]跟arr[j+1]进行比较,所以为了保证arr[j+1]不越界,j<len-i-1
for (int l = 0; l < arr.length - i - 1; l++) {
if (arr[l] > arr[l + 1]) {
//交换两个数,//如果前一个数比后一个数大,则交换位置将大的数往后放。
arr[l + 1] = arr[l + 1] ^ arr[l];
arr[l] = arr[l + 1] ^ arr[l];
arr[l + 1] = arr[l + 1] ^ arr[l];
}
}
}
return arr;
}
2、选择排序
选择排序是比冒泡更为快速的排序方式,时间复杂度有所降低,实现思路如下:
- 将第一个值看成最小值
- 然后和后续的比较找出最小值和下标
- 交换本次遍历的起始值和最小值
- 说明:每次遍历的时候,将前面找出的最小值,看成一个有序的列表,后面的看成无序的列表,然后每次遍历无序列表找出最小值。
实现代码如下:
/**
* 选择排序
*
* @return
*/
public static int[] selectSort(int[] arr) {
//第一次循环数组
for (int i = 0; i < arr.length - 1; i++) {
//定义最小数下标
int miniIndex = i;
//第二次循环数组
for (int l = i + 1; l < arr.length; l++) {
//碰到比最小值小的,重新标记最小标
if (arr[l] < arr[miniIndex]) {
miniIndex = l;
}
}
//交换下标对于数值
if (miniIndex != i) {
arr[miniIndex] = arr[miniIndex] ^ arr[i];
arr[i] = arr[miniIndex] ^ arr[i];
arr[miniIndex] = arr[miniIndex] ^ arr[i];
}
}
return arr;
}
3、归并排序
归并排序体现了分治思想,把排序对象分割成两个,在进行比对大小,思路如下:
- 将列表按照对等的方式进行拆分
- 拆分小最小快的时候,在将最小块按照原来的拆分,进行合并
- 合并的时候,通过左右两块的左边开始比较大小。小的数据放入新的块中
- 说明:简单一点就是先对半拆成最小单位,然后将两半数据合并成一个有序的列表。
代码实现如下:
/**
* 归并排序
*
* @return
*/
public static int[] mergeSort(int[] arr) {
if (arr.length<=1) {
return arr;
}
//得到数组长度中值
int num = arr.length >> 1;
int[] left = Arrays.copyOfRange(arr, 0, num);
int[] right = Arrays.copyOfRange(arr, num, arr.length);
//合并方法,递归
return merge(mergeSort(left), mergeSort(right));
}
//归并排序合并方法
private static int[] merge(int[] a, int[] b) {
int i = 0, j = 0, k = 0;
int[] result = new int[a.length + b.length];
while (i < a.length && j < b.length) {
if (a[i] <= b[j]) {
result[k++] = a[i++];
} else {
result[k++] = b[j++];
}
}
while (i < a.length) {
result[k++] = a[i++];
}
while (j < b.length) {
result[k++] = b[j++];
}
return result;
}
4、快速排序
快速排序是最近面试常考排序方法,建议多练习;
快速排序也体现了分治思想,思路如下:
- 选择基点的值(随意,建议去下标中值)
- 将比基点值小的值放在左边,比基点值大的放在右边,这样基点左边都是比基点小的,右边都是比基点大的
- 分别对左右两边进行递归运算
代码如下:
import java.util.Arrays;
/**
* 快速排序
*/
public class QuickSort {
public static void main(String[] args) {
int[] arr = {14, 25, 255, 7, 6, 89, 52, -5, 58, -88, -9, 5845, 4};
quickSort(arr, 0, arr.length - 1);
System.out.println("arr:" + Arrays.toString(arr));
}
/**
* 排序方法
*
* @param arr 数组
* @param left 左下标
* @param right 右下标
*/
private static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int pivot = arr[(left + right) / 2];
int temp = 0;
while (l < r) {
//找到左边大于等于pivot的值下标
while (arr[l] < pivot) {
l += 1;
}
//找到右边小于等于pivot的值下标
while (arr[r] > pivot) {
r -= 1;
}
if (l >= r) {
break;
}
//交换值
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//如果交换完成后,发现arr[l]==pivot,r--,r左移一位
if (arr[l] == pivot) {
r -= 1;
}
//如果交换完成后,发现arr[l]==pivot,r--,r左移一位
if (arr[r] == pivot) {
l += 1;
}
//如果l==r,错开,否则造成栈溢出
if (l == r) {
l += 1;
r -= 1;
}
//向左递归
if (left < r) {
quickSort(arr, left, r);
}
//向右递归
if (right > l) {
quickSort(arr, l, right);
}
}
}
}