排序
1.冒泡排序
算法思想:遍历数组,比较相邻的两个元素a[i]和a[i+1],如果a[i]>a[i+1],则交换两个元素的位置(从小到大排序)。算法的时间复杂度为O(n^2), 空间复杂度为O(1),是一个稳定的算法。
java代码实现:
public class BubbleSort { public static void sort(int[] arr) { // 如果数组为null或者长度为1,无序排序 if (arr == null || arr.length == 1) { return; } // 外层循环控制排序的次数 for (int i = 0; i < arr.length; i++) { // 设置一个标志位,表示本次排序是否发生元素交换 boolean flag = false; // 内层循环表示一次排序 for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; flag = true; } } if (!flag) { // 如果本次排序没有发生交换,则说明数组已经有序 break; } } } }
2.插入排序
算法思想:初始时,将第一个元素划分为有序区,后面元素为无序区,对无序区进行排序,在有序区中查找要待排元素的插入位置,将其插入。算法的时间复杂度为O(n^2),空间复杂度O(1),是一个稳定的算法。
java代码实现:
public class InsertionSort { public static void sort(int[] arr) { // 省略部分判断代码 // 外层循环控制排序的次数 for (int i = 1; i < arr.length; i++) { // 当前待插入元素 int current = arr[i]; // 有序区的最后一个元素索引 int j = i - 1; // 从后向前遍历有序区,查找待插入元素的位置 for (; j >= 0 && arr[j] > current; j--) { arr[j + 1] = arr[j]; } // 将待插元素插入 arr[j + 1] = current; } } }
3.希尔排序
算法思想:在数组基本有序的情况下,插入排序的效率很高,为了达到这一目的,可以将数组根据一个gap进行分组,组内进行插入排序,然后逐步缩减gap,gap为1时,数组已基本有序,然后再做一次插入排序。举个栗子:数组{1, 6, 3, 8, 2, 9, 0, 4, 7, 5},首先gap为5(数组长度二分之一),分组为{1, 9},{6, 0},{3, 4},{8, 7},{2, 5},进行组间排序之后,{1, 9},{0, 6},{3, 4},{7, 8},{2, 5} -> {1, 0, 3, 7, 2, 9, 6, 4, 8, 5}然后gap缩减为2,继续分组为{1, 3, 2, 6, 8},{0, 7, 9, 4, 5},组间排序结果{1, 2, 3, 6, 8},{0, 4, 5, 7, 9}->{1, 0, 2, 4, 3, 5, 6, 7, 8, 9},最后gap缩减为1,即为插入排序,结果为{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}。希尔排序的时间复杂度取决于gap的选取,然而如何选取合适的gap是一个数学难题,希尔给出的方法是取数组长度的一半。
java代码实现:
public class ShellSort { public static void sort(int[] arr) { int gap = arr.length / 2; while (gap >= 1) { // 分组进行插入排序 for (int i = gap; i < arr.length; i++) { // 当前待插入元素 int current = arr[i]; // 有序区的最后一个元素索引 int preIndex = i - gap; // 查找待插元素的插入位置 for (; preIndex >= 0 && arr[preIndex] > current; preIndex = preIndex - gap) { arr[preIndex + gap] = arr[preIndex]; } // 将待插入元素插入 arr[preIndex + gap] = current; } gap /= 2; } } }
4.选择排序
算法思想:简单粗暴,跟小孩儿选卡片排序一样,选出来最小的放第一位,再选最小的放第二位,直到排序完成。时间复杂度为O(n^2),空间复杂度为O(1),是一个不稳定的排序。选择排序的时间和数组的初始状态没有关系,就是说在最好情况下,数组原本就是有序的,和在最坏情况下,数组是逆序,选择排序的时间都差不多,因为无论怎样,都会遍历整个数组去查找最小的元素,这方面的表现倒是挺稳定的。
java代码实现:
public class SelectionSort { public static void sort(int[] arr) { // 外层循环控制排序的次数 for (int i = 0; i < arr.length - 1; i++) { // 初始设第一个元素为最小元素 int minIndex = i; // 查找最小元素的索引 for (int j = i + 1; j < arr.length; j++) { if (arr[minIndex] > arr[j]) { minIndex = j; } } // 将最小元素交换到他最终的位置 if (minIndex != i) { int temp = arr[minIndex]; arr[minIndex] = arr[i]; arr[i] = temp; } } } }
5. 快速排序
算法思想:选取一个基准值pivot,将数组划分为两个部分(最复杂的部分是划分操作),一部分比pivot小,一部分比pivot大,这样就找到pivot的最终位置,递归对剩下的两部分进行快速排序。时间复杂度为O(nlogn),空间复杂度为O(1),是一个稳定的算法 。快排是第一个突破O(n^2)的排序算法。
java代码实现:
public class QuickSort { public static void sort(int[] arr) { sort(arr, 0, arr.length - 1); } private static void sort(int[] arr, int left, int right) { // 边界条件 if (left >= right) { return; } int index = partition(arr, left, right); // 递归 sort(arr, left, index - 1); sort(arr, index + 1, right); } private static int partition(int[] arr, int left, int right) { // 将左边的元素选为基准值 int pivot = arr[left]; while (left < right) { while (left < right && arr[right] >= pivot) { right--; } arr[left] = arr[right]; while (left < right && arr[left] <= pivot) { left++; } arr[right] = arr[left]; } arr[left] = pivot; return left; } }
6.归并排序
算法思想:利用分治的思想,将大数组不停的分成小数组,直到划分到只含一个元素,只有一个元素的数组肯定是有序,然后将两个有序的数组进行归并,直到原数组有序。时间复杂度为O(nlogn),空间复杂度为O(n),是稳定的算法。
java代码实现:
public class MergeSort { public static void sort(int[] arr) { sort(arr, 0, arr.length - 1); } private static void sort(int[] arr, int left, int right) { if (left >= right) { return; } int mid = (right + left) / 2; // 递归 sort(arr, left, mid); sort(arr, mid + 1, right); // 归并 merge(arr, left, mid, right); } private static void merge(int[] arr, int left, int mid, int right) { // 新建一个数组,用来存放排序后的数据 int[] temp = new int[right - left + 1]; int i = left; int j = mid + 1; int k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } while (i <= mid) { temp[k++] = arr[i++]; } while (j <= right) { temp[k++] = arr[j++]; } // 将排序后的数组赋给原数组区间 for (int p = 0; p < temp.length; p++) { arr[left + p] = temp[p]; } } }
7.堆排序
算法思想:利用大顶堆的根节点是最大值,将数组调整为大顶堆,然后将根元素与最后一个元素交换,再将去除最大值的数组调整为大顶堆,重复上述操作。时间复杂度为O(nlogn),空间复杂度为O(1),是一个不稳定的算法。
java代码实现:
public class HeapSort { public static void sort(int[] arr) { // 初始化堆 buildHeap(arr); // len表示无序区的长度 int len = arr.length; while (len > 1) { swap(arr, 0, len - 1); len--; // 调整为大顶堆 heapfy(arr, 0, len); } } private static void heapfy(int[] arr, int i, int len) { // 判断索引i是否有孩子 int index = 2 * i + 1; if (index >= len) { return; } // 索引为i的结点至少有一个孩子 if (index + 1 < len) { if (arr[index] < arr[index + 1]) { index++; } } if (arr[i] < arr[index]) { swap(arr, i, index); heapfy(arr, index, len); } } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } private static void buildHeap(int[] arr) { int len = arr.length; // 从下到上依次调整为大顶堆 for (int i = (arr.length - 2) / 2; i >= 0; i--) { heapfy(arr, i, len); } } }
ps:刚开始写博客,难免有疏漏的地方,而且感觉自己写的也不是很清楚,附上大佬的文章。
posted on 2019-07-03 22:29 sweetcookie 阅读(100) 评论(0) 收藏 举报
浙公网安备 33010602011771号