冒泡排序
冒泡排序是最简单的排序之一了,其大体思想就是通过与相邻元素的比较和交换来把小的数交换到最前面。这个过程类似于水泡向上升一样,因此而得名。时间复杂度O(n ^ 2),稳定排序。
package com.yxx.algorithm.sort;
import static com.yxx.algorithm.sort.Util.*;
/**
* 冒泡排序
* 时间复杂度 O(n ^ 2)
*/
public class BubbleSort {
/**
* 通过与相邻元素比较,把最小的换到最前面
*/
public static void bubbleSort(int[] array) {
if (array == null || array.length == 0) {
return;
}
boolean flag;
for (int length = array.length, i = 0; i < length - 1; i++) {
flag = true;
for (int j = length - 1; j > i; j--) {
if (array[j - 1] > array[j]) {
swap(array, j, j - 1);
flag = false;
}
}
if (flag) {
break;
}
}
}
public static void main(String[] args) {
printArray(ARRAY);
bubbleSort(ARRAY);
printArray(ARRAY);
}
}
选择排序
选择排序的思想其实和冒泡排序有点类似,但过程不同。冒泡排序是通过和相邻的元素比较、交换,选择排序是对整体的进行遍历,通过比较获取最小元素进行交换。其实选择排序可以看成冒泡排序的优化,因为其目的相同,只是选择排序只有在确定了最小数的前提下才进行交换,大大减少了交换的次数。选择排序的时间复杂度为O(n^2)。
package com.yxx.algorithm.sort;
/**
* 选择排序
* 时间复杂度O(n ^ 2)
*/
public class ChoseSort {
/**
* 每次和最小的数交换
*/
public static void choseSort(int[] array) {
if (array == null || array.length == 0) {
return;
}
for (int i = 0; i < array.length - 1; i++) {
int mixIndex = i;
for (int j = i + 1; j < array.length; j++) {
if (array[j] < array[mixIndex]) {
mixIndex = j;
}
}
Util.swap(array, mixIndex, i);
}
}
public static void main(String[] args) {
choseSort(Util.ARRAY);
Util.printArray(Util.ARRAY);
}
}
插入排序
插入排序通过找到合适的位置插入来进行排序。通过不断比较待插入元素和已有元素,来确定插入位置。注意在插入一个数的时候要保证这个数前面的数已经有序。简单插入排序的时间复杂度也是O(n^2)。
package com.yxx.algorithm.sort;
/**
* 插入排序
* 时间复杂度 O(n ^ 2)
*/
public class InsertSort {
/**
* 一个一个往里插入
*/
public static void insertSort(int[] array) {
if (!Util.isValidArray(array)) {
return;
}
for (int i = 1; i < array.length; i++) { // 从第二个索引开始
int target = array[i];
int j = i;
while (j > 0 && array[j - 1] > target) {
array[j] = array[j - 1]; // 元素后移
j--; // 指针前移
}
array[j] = target;
}
}
public static void main(String[] args) {
insertSort(Util.ARRAY);
Util.printArray(Util.ARRAY);
}
}
快速排序
快速排序在实际应用中确实是表现最好的排序算法。快速排序通过确定一个基准数和左、右指针,左指针找比基准数大的数,右指针找比基准数小的数,然后进行交换,直到两指针相遇,然后和基准数进行交换,根据相遇位置对左右两个子序列进行递归排序。快速排序是不稳定的,其时间平均时间复杂度是O(nlgn)。
package com.yxx.algorithm.sort;
import sun.net.www.protocol.http.AuthenticationInfo;
/**
* 快速排序
* 时间复杂度 O(nlgn)
* 不稳定
* 冒泡+二分+递归分治
*
*/
public class QuickSort {
private static void quickSort(int[] array) {
int left = 0;
int right = array.length - 1;
quickSort(array, left, right);
}
private static void quickSort(int[] array, int left, int right) {
if (left >= right) {
return;
}
int newLeft = partition(array,left,right);
quickSort(array, left, newLeft - 1);
quickSort(array, newLeft + 1, right);
}
private static int partition(int[] array,int left,int right) {
int pivotKey = array[left];
int pivotPoint = left;
while (left < right) {
//右指针找比基准小的数
while (left < right && array[right] >= pivotKey) {
right--;
}
//左指针找比基准大的数
while (left < right && array[left] <= pivotKey) {
left++;
}
Util.swap(array, left, right);
}
//交换基准和找到的位置的值
Util.swap(array, left, pivotPoint);
array[left] = pivotKey;
return left;
}
public static void main(String[] args) {
Util.printArray(Util.ARRAY);
quickSort(Util.ARRAY);
Util.printArray(Util.ARRAY);
}
}
希尔排序
希尔排序是插入排序的一种高效率的实现,也叫缩小增量排序。基本思想:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时再对全体记录进行一次直接插入排序。
希尔排序的分析是复杂的,时间复杂度是所取增量的函数,这涉及一些数学上的难题。但是在大量实验的基础上推出当n在某个范围内时,时间复杂度可以达到O(n^1.3)。
package com.yxx.algorithm.sort;
/**
* 希尔排序 - 希尔排序是插入排序的一种高效率的实现,也叫缩小增量排序
* <p>
* 希尔增量
*/
public class ShellInsert {
public static void shellSort(int[] array) {
if (!Util.isValidArray(array)) {
return;
}
int step = array.length / 2;
while (step >= 1) {
shellInsert(array, step);
step /= 2;
}
}
private static void shellInsert(int[] array, int step) {
for (int i = step; i < array.length; i++) {
int target = array[i];
int j = i;
while (j >= step && array[j - step] > target) {
array[j] = array[j - step];
j -= step;
}
array[j] = target;
}
}
public static void main(String[] args) {
Util.printArray(Util.ARRAY);
shellSort(Util.ARRAY);
Util.printArray(Util.ARRAY);
}
}
归并排序
归并排序使用了递归分治的思想。速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(n)
最差时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定
package com.yxx.algorithm.sort;
/**
* 归并排序
* 时间复杂度O(nlgn)
*/
public class MergeSort {
public static void main(String[] args) {
Util.printArray(Util.ARRAY);
mergeSort(Util.ARRAY);
Util.printArray(Util.ARRAY);
}
public static void mergeSort(int[] array) {
int length = array.length;
int[] temp = new int[length];
merge_sort_recursive(array, temp, 0, length - 1);
}
// 归并排序(Java-递归版)
static void merge_sort_recursive(int[] arr, int[] temp, int start, int end) {
if (start >= end) {
return;
}
int mid = (end - start) / 2 + start;//中间位置
merge_sort_recursive(arr, temp, start, mid);//递归左子序列
merge_sort_recursive(arr, temp, mid + 1, end);//递归右子序列
merge(arr, temp, start, mid, end);//合并序列
}
private static void merge(int[] arr, int[] temp, int start, int mid, int end) {
int i = start;
int j = mid + 1;
int t = 0;
while (i <= mid && j <= end) {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
while (i <= mid) {
temp[t++] = arr[i++];
}
while (j <= end) {
temp[t++] = arr[j++];
}
for (int k = 0; k < t; k++) {
arr[start++] = temp[k];
}
}
}