常见的几种排序整理
- 冒泡排序
- 选择排序
- 插入排序
- 希尔排序
- 快速排序
- 归并排序
- 堆排序
冒泡排序
思想:对比当前值的下一个值,如果大就交换位置
代码:
/*** 冒泡排序*/
public class bubbleSort {public static void main(String[] args) {int[] array = {1, 5, 3, 2, 4};bubbleSort(array);System.out.println(Arrays.toString(array));}public static void bubbleSort(int[] array) {for (int i = 0; i < array.length; i++) {for (int j = i + 1; j < array.length; j++) {if (array[i] > array[j]) {int temp = array[j];array[j] = array[i];array[i] = temp;}}}}
}
选择排序
思想:选择当前数组中最小的一个值放在起始位置,再从剩下的数组值中选择第二小的值放在前面值的后面,直到选完。
代码:
/*** 选择排序*/
public class SelectSort {public static void main(String[] args) {int[] array = {1, 5, 3, 2, 4};selectSort(array);System.out.println(Arrays.toString(array));}public static void selectSort(int[] array) {for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i + 1; j < array.length; j++) {if (array[minIndex] > array[j]) {minIndex = j;}}int temp = array[minIndex];array[minIndex] = array[i];array[i] = temp;}}
}
插入排序
思想:
- 首先从第一个元素开始,该元素被认为是有序的;
- 取出下一个元素,在已经排序的元素序列中从后往前进行扫描;
- 如果该已排好序的元素大于新元素,则将该元素移到下一位置;
- 重复步骤3一直往前进行扫描比较,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
代码:
public class InsertSort {public static void main(String[] args) {int[] array = {1, 5, 3, 2, 4};insertSort(array);System.out.println(Arrays.toString(array));}public static void insertSort(int[] a) {for (int i = 1; i < a.length; i++) {int j = i - 1;int current = a[i];while (a[j] > current && j > 0) {a[j + 1] = a[j];j--;}a[j + 1] = current;}}
}
希尔排序
思想:更加高效的排序,是插入排序的升级版,总的来说就是先分组做插入排序,最后当gap为1时,再对整个数组进行一次插入排序,这时候数组基本有序,所以最后一次插入排序耗时很低。
代码:
public class ShellSort {public static void main(String[] args) {int[] array = {1, 5, 3, 2, 4};shellSort(array);System.out.println(Arrays.toString(array));}public static void shellSort(int[] a) {int len = a.length;int temp;int j;for (int gap = len / 2; gap >= 1; gap = gap / 2) {for (int i = gap; i < len; i++) {temp = a[i];j = i - gap;while (j > 0 && a[j] > temp) {a[j + gap] = a[j];j -= gap;}a[j + gap] = temp;}}}
}
快速排序
思想: 选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
public class QuickSort {public static void main(String[] args) {int[] arr = {10, 7, 8, 9, 1, 5};quickSort(arr, 0, arr.length - 1);System.out.println(Arrays.toString(arr));}public static void quickSort(int[] arr, int low, int high) {if (low < high) {// pi 是分区索引,arr[p] 现在已经到位int pi = partition(arr, low, high);// 分别对 pi 左边和右边的子数组进行递归排序quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}}// 这个函数将数组分为两部分,并返回分区索引public static int partition(int[] arr, int low, int high) {int pivot = arr[high]; // 选择最右边的元素作为主元int i = (low - 1); // 指向最小元素的指针for (int j = low; j <= high - 1; j++) {// 如果当前元素小于或等于主元if (arr[j] <= pivot) {i++;// 交换 arr[i] 和 arr[j]int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}// 交换 arr[i+1] 和 arr[high] (或主元)int temp = arr[i + 1];arr[i + 1] = arr[high];arr[high] = temp;return i + 1;}
}
归并排序
思想:采用分治法,从中间拆分为2个子组,然后递归拆分子组直到每个子组数量为1,不断的将相邻两个子组合并并且排序直到只剩一个组
代码:
public class mergeSortTest {public static void main(String[] args) {int[] array = {1, 5, 3, 2, 4};mergeSort(array);System.out.println(Arrays.toString(array));}public static void mergeSort(int[] array) {if (array == null || array.length == 1) {return;}mergeSort(array, 0, array.length - 1);}public static void mergeSort(int[] array, int left, int right) {if (left < right) {int mid = (left + right) / 2;// 对左半部分进行归并排序mergeSort(array, left, mid);// 对右半部分进行归并排序mergeSort(array, mid + 1, right);// 合并两个有序数组merge(array, left, mid, right);}}//合并左右两侧子数组public static void merge(int[] array, int left, int mid, int right) {//临时数组int[] temp = new int[right - left + 1];//左边指针int p1 = left;//右侧指针int p2 = mid + 1;//临时数组下标int tempIndex = 0;//此步就是合并左右两边,然后比大小,排序while (p1 <= mid && p2 <= right) {temp[tempIndex++] = array[p1] < array[p2] ? array[p1++] : array[p2++];}while (p1 <= mid) {temp[tempIndex++] = array[p1++];}while (p2 <= right) {temp[tempIndex++] = array[p2++];}//将临时数组的元素复制回原数组if (tempIndex >= 0) System.arraycopy(temp, 0, array, left, tempIndex);}
}
堆排序
思想:
堆排序是一种基于二叉堆(通常是大顶堆或小顶堆)的比较排序算法。其基本思想是将待排序的序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个序列重新构造成一个堆,这样会得到n个元素中的次大值。 如此反复执行,便能得到一个有序序列了。
代码:
public class HeapSort {public static void main(String[] args) {int[] arr = {10, 7, 8, 9, 1, 5, 3, 5, 5, 2, 0, 6, 0, 9};sort(arr);System.out.println(Arrays.toString(arr));}public static void sort(int arr[]) {int n = arr.length;// 构建最大堆(从最后一个非叶子节点开始)for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}// 一个一个从堆顶取出元素,将堆顶元素沉到数组末端for (int i = n - 1; i >= 0; i--) {int temp = arr[0];arr[0] = arr[i];arr[i] = temp;// 重新调整堆 heapify(arr, i, 0);}}// 调整堆/*** 调整堆* 关键解释:* 大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]* 小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]*/static void heapify(int arr[], int n, int i) {int largest = i; // 初始化最大值为根 int left = 2 * i + 1; // 左 = 2*i + 1int right = 2 * i + 2; // 右 = 2*i + 2// 如果左子节点大于根 if (left < n && arr[left] > arr[largest])largest = left;// 如果右子节点大于目前已知的最大值 if (right < n && arr[right] > arr[largest])largest = right;// 如果最大值不是根 if (largest != i) {int swap = arr[i];arr[i] = arr[largest];arr[largest] = swap;// 递归调整受影响的子堆 heapify(arr, n, largest);}}
}