冒泡排序
算法步骤
从前往后不断的两两比较,这样当前最大的元素总是会排在最后面。所以称为冒泡。
图解算法
代码实现
public static int[] bubbleSort(int[] arr) { // i是排好了几个数 for (int i = 1; i < arr.length; i++) { // flag标记当前循环是否调整了顺序,如果没有调整,说明排序完成 boolean flag = true; // arr.length - i控制数组尾巴 for (int j = 0; j < arr.length - i; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = false; } } if (flag) { break; } } return arr; }算法分析
稳定性:稳定
时间复杂度:最佳:O(n)O(n)O(n) ,最差:O(n2)O(n^2)O(n2), 平均:O(n2)O(n^2)O(n2)
空间复杂度:O(1)O(1)O(1)
排序方式:内部排序
选择排序
算法步骤
从前往后不断地选择最小/最大的元素和当前未排序序列的头进行交换
图解算法
代码实现
public static int[] selectionSort(int[] arr) { // 找到的元素放到第i个,未排序序列头 for (int i = 0; i < arr.length - 1; i++) { // minIndex记录当前未排序的最小元素的索引 int minIndex = i; for (int j = i + 1; j < arr.length; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } // 交换 if (minIndex != i) { int tmp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = tmp; } } return arr; }算法分析
稳定性:不稳定
时间复杂度:最佳:O(n2)O(n^2)O(n2) ,最差:O(n2)O(n^2)O(n2), 平均:O(n2)O(n^2)O(n2)
空间复杂度:O(1)O(1)O(1)
排序方式:内部排序
插入排序
算法步骤
就是扑克牌理牌。读取未排列序列的元素,拿到新元素后从后往前遍历已排序序列找到合适的位置插入。
图解算法
代码实现
public static int[] insertionSort(int[] arr) { for (int i = 1; i < arr.length; i++) { // preindex记录已排序序列的尾 int preIndex = i - 1; // current是当前要插入的元素 int current = arr[i]; while (preIndex >= 0 && current < arr[preIndex]) { // 往后移 arr[preIndex + 1] = arr[preIndex]; preIndex -= 1; } arr[preIndex + 1] = current; } return arr; }算法分析
稳定性:稳定
时间复杂度:最佳:O(n)O(n)O(n) ,最差:O(n2)O(n^2)O(n2), 平均:O(n2)O(n^2)O(n2)
空间复杂度:O(1)O(1)O(1)
排序方式:内部排序
希尔排序
算法步骤
不断的按照增量来分出子数组的数量,子数组内部进行插入排序,然后缩小增量,减少分子数组的数量,然后接着插入排序,直到增量为1之后再进行一次插入排序即可。
算法图解
代码实现
public static int[] shellSort(int[] arr) { int n = arr.length; int gap = n / 2; while (gap > 0) { for (int i = gap; i < n; i++) { int current = arr[i]; int preIndex = i - gap; // 插入排序 while (preIndex >= 0 && arr[preIndex] > current) { arr[preIndex + gap] = arr[preIndex]; preIndex -= gap; } arr[preIndex + gap] = current; } gap /= 2; } return arr; }算法分析
稳定性:不稳定
时间复杂度:最佳:O(nlogn)O(nlogn)O(nlogn), 最差:O(n2)O(n^2)O(n2) 平均:O(nlogn)O(nlogn)O(nlogn)
空间复杂度:O(1)O(1)O(1)
排序方式:内部排序
归并排序
算法步骤
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
就是让子数列内部有序,然后让两个子序列段间有序,不断重复直到整个序列有序。图解算法
代码实现
public static int[] mergeSort(int[] arr) { if (arr.length <= 1) { return arr; } int middle = arr.length / 2; int[] arr_1 = Arrays.copyOfRange(arr, 0, middle); int[] arr_2 = Arrays.copyOfRange(arr, middle, arr.length); return merge(mergeSort(arr_1), mergeSort(arr_2)); } public static int[] merge(int[] arr_1, int[] arr_2) { int[] sorted_arr = new int[arr_1.length + arr_2.length]; int idx = 0, idx_1 = 0, idx_2 = 0; while (idx_1 < arr_1.length && idx_2 < arr_2.length) { if (arr_1[idx_1] < arr_2[idx_2]) { sorted_arr[idx] = arr_1[idx_1]; idx_1 += 1; } else { sorted_arr[idx] = arr_2[idx_2]; idx_2 += 1; } idx += 1; } if (idx_1 < arr_1.length) { while (idx_1 < arr_1.length) { sorted_arr[idx] = arr_1[idx_1]; idx_1 += 1; idx += 1; } } else { while (idx_2 < arr_2.length) { sorted_arr[idx] = arr_2[idx_2]; idx_2 += 1; idx += 1; } } return sorted_arr; }算法分析
稳定性:稳定
时间复杂度:最佳:O(nlogn)O(nlogn)O(nlogn), 最差:O(nlogn)O(nlogn)O(nlogn), 平均:O(nlogn)O(nlogn)O(nlogn)
空间复杂度:O(n)O(n)O(n)
排序方式:外部排序
快速排序
算法步骤
从序列中随机挑出一个元素,做为 基准;通过一趟排序将待排序列分隔成独立的两部分,比基准小的在左边,比基准大的在右边,则可分别对这两部分子序列继续进行排序,以达到整个序列有序。
图解算法
代码实现
public static int partition(int[] array, int low, int high) { int pivot = array[high]; int pointer = low; for (int i = low; i < high; i++) { if (array[i] <= pivot) { int temp = array[i]; array[i] = array[pointer]; array[pointer] = temp; pointer++; } System.out.println(Arrays.toString(array)); } int temp = array[pointer]; array[pointer] = array[high]; array[high] = temp; return pointer; } public static void quickSort(int[] array, int low, int high) { if (low < high) { int position = partition(array, low, high); quickSort(array, low, position - 1); quickSort(array, position + 1, high); } }算法分析
稳定性:不稳定
时间复杂度:最佳:O(nlogn)O(nlogn)O(nlogn), 最差:O(n2)O(n^2)O(n2),平均:O(nlogn)O(nlogn)O(nlogn)
空间复杂度:O(logn)O(logn)O(logn)
排序方式:内部排序
堆排序
算法步骤
堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子结点的值总是小于(或者大于)它的父节点。
图解算法
算法分析
稳定性:不稳定
时间复杂度:最佳:O(nlogn)O(nlogn)O(nlogn), 最差:O(nlogn)O(nlogn)O(nlogn), 平均:O(nlogn)O(nlogn)O(nlogn)
空间复杂度:O(1)O(1)O(1)
排序方式:内部排序
计数排序
算法步骤
- 使用一个额外的数组 C,其中第 i 个元素是待排序数组 A 中值等于 i 的元素的个数。然后根据数组 C 来将 A 中的元素排到正确的位置。
- 对 C 数组变形,新元素的值是该元素与前一个元素值的和,即当 i>1 时 C[i] = C[i] + C[i-1]:目的是为了确定每个元素在排序后数组中的正确位置。
图解算法
代码实现
// 获取最大最小值 private static int[] getMinAndMax(int[] arr) { int maxValue = arr[0]; int minValue = arr[0]; for (int i = 0; i < arr.length; i++) { if (arr[i] > maxValue) { maxValue = arr[i]; } else if (arr[i] < minValue) { minValue = arr[i]; } } return new int[] { minValue, maxValue }; } public static int[] countingSort(int[] arr) { if (arr.length < 2) { return arr; } int[] extremum = getMinAndMax(arr); int minValue = extremum[0]; int maxValue = extremum[1]; int[] countArr = new int[maxValue - minValue + 1]; int[] result = new int[arr.length]; for (int i = 0; i < arr.length; i++) { countArr[arr[i] - minValue] += 1; } for (int i = 1; i < countArr.length; i++) { countArr[i] += countArr[i - 1]; } for (int i = arr.length - 1; i >= 0; i--) { int idx = countArr[arr[i] - minValue] - 1; result[idx] = arr[i]; countArr[arr[i] - minValue] -= 1; } return result; }算法分析
稳定性:稳定
时间复杂度:最佳:O(n+k)O(n+k)O(n+k) 最差:O(n+k)O(n+k)O(n+k) 平均:O(n+k)O(n+k)O(n+k)
空间复杂度:O(k)O(k)O(k)
排序方式:外部排序
桶排序
算法步骤
遍历输入数据,并且把数据依次映射到对应的桶里去。对每个非空的桶进行排序。从非空桶里把排好序的数据拼接起来。
图解算法
算法分析
稳定性:稳定
时间复杂度:最佳:O(n+k)O(n+k)O(n+k) 最差:O(n2)O(n^2)O(n2) 平均:O(n+k)O(n+k)O(n+k)
空间复杂度:O(n+k)O(n+k)O(n+k)
排序方式:外部排序
基数排序
算法步骤
- 对元素中的每一位数字进行排序,从最低位开始排序。按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。
- A 为原始数组,从最低位开始取每个位组成 radix 数组;对 radix 进行计数排序(利用计数排序适用于小范围数的特点)。
图解算法
算法实现
public static int[] radixSort(int[] arr) { if (arr.length < 2) { return arr; } int N = 1; int maxValue = arr[0]; for (int element : arr) { if (element > maxValue) { maxValue = element; } } while (maxValue / 10 != 0) { maxValue = maxValue / 10; N += 1; } for (int i = 0; i < N; i++) { List<List<Integer>> radix = new ArrayList<>(); for (int k = 0; k < 10; k++) { radix.add(new ArrayList<Integer>()); } for (int element : arr) { int idx = (element / (int) Math.pow(10, i)) % 10; radix.get(idx).add(element); } int idx = 0; for (List<Integer> l : radix) { for (int n : l) { arr[idx++] = n; } } } return arr; }算法分析
稳定性:稳定
时间复杂度:最佳:O(n×k)O(n×k)O(n×k) 最差:O(n×k)O(n×k)O(n×k) 平均:O(n×k)O(n×k)O(n×k)
空间复杂度:O(n+k)O(n+k)O(n+k)
排序方式:外部排序
计数排序 vs 桶排序 vs 基数排序
这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
- 计数排序:每个桶只存储单一键值(出现了几次)
- 桶排序:每个桶存储一定范围的数值(桶内部排序)
- 基数排序:根据键值的每位数字来分配桶(从数字的低位数到高位数排序)
排序算法总结
- 比较类排序是通过比较来决定元素间的相对次序。比较类排序的优势是,适用于各种规模的数据,也不在乎数据的分布,都能进行排序。可以说,比较排序适用于一切需要排序的情况。
- 非比较排序是要确定每个元素之前的已有的元素个数。非比较排序时间复杂度底,但由于非比较排序需要占用空间来确定唯一位置。所以对数据规模和数据分布有一定的要求。












1267

被折叠的 条评论
为什么被折叠?



