1.冒泡排序
从第一个元素开始,比较相邻的两个元素,顺序错误便交换位置,重复上面步骤,遍历完整个数组后,最大的元素已经移动到末尾,下一轮便可少比较一个元素。
当一轮遍历中没有发生任何交换时,说明数组有序,可以提前终止排序过程。
最好O(n),最差O(n^2)
public static void bubbleSortOpt(int[] arr) {if(arr.length < 2 || arr == null) {return;}int temp = 0;for(int i = 0; i < arr.length - 1; i++) {for(int j = 0; j < arr.length - i - 1; j++) {if(arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}for (int a = 0; a < arr.length; a++) {System.out.print(arr[a]+" ");}System.out.println();}
}/**
输入:{3,6,2,7,5,9}3 2 6 5 7 9
2 3 5 6 7 9
2 3 5 6 7 9
2 3 5 6 7 9
2 3 5 6 7 9
*/
2.快速排序
从数组中随机挑选一个元素作为基准,所有比基准元素小的元素放在基准元素前面,大的放在后面。然后递归的将左边和右边两个子数组进行排序。平均时间复杂度为O(n logn),最坏时间复杂度为O(n^2)
public void quicksort(int[] arr, int start, int end) {if(start < end) {// 把数组中的首位数字作为基准数int stard = arr[start];// 记录需要排序的下标int low = start;int high = end;// 循环找到比基准数大的数和比基准数小的数while(low < high) {// 右边的数字比基准数大while(low < high && arr[high] >= stard) {high--;}// 使用右边的数替换左边的数arr[low] = arr[high];// 左边的数字比基准数小while(low < high && arr[low] <= stard) {low++;}// 使用左边的数替换右边的数arr[high] = arr[low];}// 把标准值赋给下标重合的位置arr[low] = stard;// 处理所有小的数字quickSort(arr, start, low);// 处理所有大的数字quickSort(arr, low + 1, end);}
}
3.插入排序
将数组的一个元素视为以排序部分,其余为未排序部分,从未排序部分选择一个元素,插入已排序部分的正确位置。为了插入,将已排序部分中大于待插入元素向右移动一个位置。最好是O(n),最坏时间复杂度为O(n^2)。
插入排序在数据有序时效率最高。
public void insertSort(int[] arr) {// 遍历所有数字for(int i = 1; i < arr.length - 1; i++) {// 当前数字比前一个数字小if(arr[i] < arr[i - 1]) {int j;// 把当前遍历的数字保存起来int temp = arr[i];for(j = i - 1; j >= 0 && arr[j] > temp; j--) {// 前一个数字赋给后一个数字arr[j + 1] = arr[j];}// 把临时变量赋给不满足条件的后一个元素arr[j + 1] = temp;}}
}
4.希尔排序
将数据分按照一定间隔分为若干组,对每组的 元素进行插入排序,完成一组后,间隔减半,直到间隔为1。平均时间复杂度为O(n logn),最坏时间复杂度为O(n^2)
public void shellSort(int[] arr) {// gap 为步长,每次减为原来的一半。for (int gap = arr.length / 2; gap > 0; gap /= 2) {// 对每一组都执行直接插入排序for (int i = 0 ;i < gap; i++) {// 对本组数据执行直接插入排序for (int j = i + gap; j < arr.length; j += gap) {// 如果 a[j] < a[j-gap],则寻找 a[j] 位置,并将后面数据的位置都后移if (arr[j] < arr[j - gap]) {int k;int temp = arr[j];for (k = j - gap; k >= 0 && arr[k] > temp; k -= gap) {arr[k + gap] = arr[k];}arr[k + gap] = temp;}}}}
}
5.选择排序
每次从未排序的选出最大或者最小的,与当前元素交换位置。最坏和平均都为O(n²),空间复杂度为O(1)。
public void selectSort(int[] arr) {// 遍历所有的数for (int i = 0; i < arr.length; i++) {int minIndex = i;// 把当前遍历的数和后面所有的数进行比较,并记录下最小的数的下标for (int j = i + 1; j < arr.length; j++) {if (arr[j] < arr[minIndex]) {// 记录最小的数的下标minIndex = j;}}// 如果最小的数和当前遍历的下标不一致,则交换if (i != minIndex) {int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}
}
6.堆排序
堆排序不稳定
/*** 转化为大顶堆* @param arr 待转化的数组* @param size 待调整的区间长度* @param index 结点下标*/
public void maxHeap(int[] arr, int size, int index) {// 左子结点int leftNode = 2 * index + 1;// 右子结点int rightNode = 2 * index + 2;int max = index;// 和两个子结点分别对比,找出最大的结点if (leftNode < size && arr[leftNode] > arr[max]) {max = leftNode;}if (rightNode < size && arr[rightNode] > arr[max]) {max = rightNode;}// 交换位置if (max != index) {int temp = arr[index];arr[index] = arr[max];arr[max] = temp;// 因为交换位置后有可能使子树不满足大顶堆条件,所以要对子树进行调整maxHeap(arr, size, max);}
}/*** 堆排序* @param arr 待排序的整型数组*/
public static void heapSort(int[] arr) {// 开始位置是最后一个非叶子结点,即最后一个结点的父结点int start = (arr.length - 1) / 2;// 调整为大顶堆for (int i = start; i >= 0; i--) {SortTools.maxHeap(arr, arr.length, i);}// 先把数组中第 0 个位置的数和堆中最后一个数交换位置,再把前面的处理为大顶堆for (int i = arr.length - 1; i > 0; i--) {int temp = arr[0];arr[0] = arr[i];arr[i] = temp;maxHeap(arr, i, 0);}
}
7.归并排序
将数组分为两个子数组,分别对子数组调用归并排序,好最坏时间复杂度都相同O(n logn)
https://mp.weixin.qq.com/s?__biz=MzAxMjY5NDU2Ng==&mid=2651862169&idx=1&sn=e011e79ff77736dfb389084bb3a20d37&chksm=804971d0b73ef8c649d7c9b08706f3c33b0e10c3935e24982337b05d69f1487ace072fbd48d9&scene=27