冒泡排序
如果序列尾部已经局部有序,可以记录最后1次交换的位置,减少比较次数
public class BubbleSort {
public static void main(String[] args) {
int[] array = {2, 3, 1, 5, 8, 4};
//如果序列尾部已经局部有序,可以记录最后1次交换的位置,减少比较次数
for (int j = array.length - 1; j > 0; j--) {
//设置初始值为1,当数组完全有序的时候扫描一轮就结束
int sortindex = 1;
for (int i = 1; i <= j; i++) {
if (array[i] < array[i - 1]) {
int tmp = array[i - 1];
array[i - 1] = array[i];
array[i] = tmp;
sortindex = i;
}
}
j = sortindex;//记录最后一次交换的记录
}
for (int k = 0; k < array.length; k++) {
System.out.print(array[k]+" ");
}
}
}
选择排序
选择排序的交换次数要远远少于冒泡排序,平均性能优于冒泡排序
最好,最坏,平均时间复杂度:O(n^2),空间复杂度:O(1),属于稳定排序
public class SelectionSort {
public static void main(String[] args) {
int[] array = {2,3,1,5,7,8,6};
//从序列中找出最大的那个元素,然后与最末尾的元素交换位置
for (int i = array.length - 1; i > 0; i--) {
int maxIndex = 0;
for (int j = 1; j <= i; j++) {
if (array[maxIndex] <= array[j]) {
maxIndex = j;
}
}
int tmp = array[maxIndex];
array[maxIndex] = array[i];
array[i] = tmp;
}
for (int k = 0; k < array.length; k++) {
System.out.print(array[k]+" ");
}
}
}
插入排序
与选择排序的区别在于前面排序的对象是暂时稳定的排序,
对于有序数组,插入排序的复杂度是O(n),整体的复杂度是O(n^ 2),而选择排序是稳定的排序算法,O(n^2)
public class InsertionSort {
private InsertionSort() {
}
public static <E extends Comparable<E>> void sort(E[] arr) {
for (int i = 0; i < arr.length; i++) {
//将arr[i]插入到合适位置
E t = arr[i];
int j;//实际存储的位置
for (j = i;j - 1 >0 && t.compareTo(arr[j-1])<0;j--){
arr[j] = arr[j-1];//前面的元素向后平移
}
arr[j] = t;
}
}
public static void main(String[] args) {
Integer[] arr = {1, 4, 2, 3, 6, 5};
InsertionSort.sort(arr);
for (int e : arr)
System.out.print(e + " ");
System.out.println();
}
}
希尔排序
归并排序
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治策略。
归并排序的时间复杂度是O(nlogn)。
public class MergeSort {
private MergeSort() {
}
public static <E extends Comparable<E>> void sort(E[] arr) {
sort(arr, 0, arr.length - 1);
}
private static <E extends Comparable<E>> void sort(E[] arr, int l, int r) {
if (l >= r) return;
int mid = (l + r) / 2;
sort(arr, l, mid);
sort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
//合并两个有序区间, arr[l..mid]和arr[mid+1..r]
private static <E extends Comparable<E>> void merge(E[] arr, int l, int mid, int r) {
E[] temp = Arrays.copyOfRange(arr, l, r + 1);//前闭后开
int i = l, j = mid + 1;
//每轮循环为arr[k]赋值
for (int k = l; k <= r; k++) {
if (i > mid) {
arr[k] = temp[j - l];
j++;
} else if (j > r) {
arr[k] = temp[i - 1];
i++;
} else if (temp[i - l].compareTo(temp[j - l]) < 0) {
arr[k] = temp[i - l];
i++;
} else {
arr[k] = temp[j - l];
j++;
}
}
}
public static void main(String[] args) {
Integer[] arr = {1, 3, 5, 7, 2, 4, 6, 8};
sort(arr);
System.out.println(Arrays.toString(arr));
}
}
快速排序
堆排序
堆排序可以认为是对选择排序的一种优化,堆排序的时间复杂度为nlogn
- 对序列进行原地建堆
- 重复执行以下操作,直到堆的元素数量为1
- 交换堆顶元素与尾元素
- 对0位置进行1次siftDown操作
public class HeapSort {
public static void main(String[] args) {
int arr[] = {2,3,1,5,4,7,9,0,8,6};
heapSort(arr);
System.out.println("堆排序后:");
for (int i : arr) {
System.out.print( i+" ");
}
}
private static void heapSort(int[] arr) {
//原地建堆
for (int i = (arr.length - 1) / 2; i >= 0; i--) {
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr, i, arr.length);
}
System.out.println("初始化堆:");
for (int i : arr) {
System.out.print( i+" ");
}
System.out.println();
for (int i = arr.length - 1; i > 0; i--) {
//交换堆顶元素与尾元素
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
//重新对堆进行调整
adjustHeap(arr, 0, i);
}
}
private static void adjustHeap(int[] arr, int parent, int length) {
//temp作为父结点
int temp = arr[parent];
//左孩子结点
int lChild = 2 * parent + 1;
while (lChild < length) {
//右孩子结点
int rChild = lChild + 1;
//如果有右孩子结点,且右孩子结点的值大于左孩子结点的值,选右孩子结点
if (rChild < length && arr[lChild] < arr[rChild]) {
lChild++;
}
//如果父结点的值已经大于孩子结点的值,则直接结束
if (temp >= arr[lChild]) {
break;
}
//把孩子结点的值赋给父结点
arr[parent] = arr[lChild];
//选取孩子结点的左孩子结点,继续向下筛选
parent = lChild;
lChild = 2 * lChild + 1;
}
arr[parent] = temp;
}
}