文章目录
- 文章参考于
0. 排序算法说明
-
排序的定义:按关键字的非递减或非递增顺序对一组记录进行排列的操作。
-
术语说明:
- 稳定:a == b;排序前 a 在 b 前面,排序之后 a 仍在 b 前面
- 不稳定:a == b;排序之前 a 在 b 之前,排序之后 a 可能 在 b 后面
- 内排序:所有排序操作都在内存中完成
- 外排序:大文件的排序,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。
- 时间复杂度:一个算法执行所耗费的时间。
- 空间复杂度:运行完一个程序所需内存的大小
-
排序算法复杂度总结
-
图片名词解释:
- n:数据规模
- k:“桶”的个数
- In-place:占用常数内存,不占用额外内存
- Out-place:占用额外内存
1. 冒泡排序(Bubble Sort)
-
工作原理:每次比较相邻的元素,按照要求进行交换(比如 升序排列,吧较大的元素放在后面),循环n次(n为总元素个数)。这样小的元素就会不断的“冒泡”到前面来。
-
动图演示
-
java代码
public static int[] bubbleSort(int[] nums) { if (nums == null || nums.length == 0){ return nums; } for (int i = 0; i < nums.length - 1; i++) { for(int j = i + 1; j < nums.length; j++ ){ int temp = 0; if(nums[i] > nums[j]){ temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } } } return nums; }
-
算法分析
- 时间复杂度:T(n) = O(n2)
2. 选择排序(Selection Sort)
-
工作原理:首先在未排序的序列中找到最小(大)的元素,存放到排序序列的起始位置,然后再从未排序元素中继续寻找最小(大)的元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。(表现最稳定(此稳定非彼稳定)的排序算法之一,因为无论什么数据进去都是O(n^2)的时间复杂度,所以用他的时候,数据规模越小越好)
-
动图演示
-
java代码
public static int[] selectionSort(int[] array) { if (array.length == 0) return array; for (int i = 0; i < array.length; i++) { int minIndex = i; for (int j = i; j < array.length; j++) { if (array[j] < array[minIndex]) //找到最小的数 minIndex = j; //将最小数的索引保存 } int temp = array[minIndex]; array[minIndex] = array[i]; array[i] = temp; } return array;
-
时间复杂度:T(o) = O(n2)
3. 插入排序(Insertion Sort)
-
工作原理:每次选择一个元素,跟序列中的所有元素比较,插入到合适的位置。
-
动图演示
-
java代码
public static int[] insertionSort(int[] array) { if (array.length == 0) return array; int current; for (int i = 0; i < array.length - 1; i++) { current = array[i + 1]; int preIndex = i; while (preIndex >= 0 && current < array[preIndex]) { array[preIndex + 1] = array[preIndex]; preIndex--; } array[preIndex + 1] = current; } return array; }
-
时间复杂度:T(n) = O(n2)
4. 希尔排序(Shell Sort)
-
工作原理:实质上是采用分组插入的方法。先将整个待排序记录序列分割成几组,从而减少参与直接排序的数据量,对每组分别进行直接插入排序,然后增加每组的数据量,重新分组。经过几次这样的分组,当序列基本有序时,再对全体数据进行一次直接插入排序。
-
特点:当待排序序列个数较少 且 待排序序列基本有序时,效率较高。
-
动图演示
-
过程演示
-
java代码
public static int[] ShellSort(int[] array) { int len = array.length; int temp, gap = len / 2; while (gap > 0) { for (int i = gap; i < len; i++) { temp = array[i]; int preIndex = i - gap; while (preIndex >= 0 && array[preIndex] > temp) { array[preIndex + gap] = array[preIndex]; preIndex -= gap; } array[preIndex + gap] = temp; } gap /= 2; } return array; }
-
时间复杂度:T(n) = O(nlog2n)
5. 归并排序(Merge Sort)
-
工作原理:将两个或两个以上的有序表合为一个有序表的过程
二路归并:将n个元素的序列,两两归并,得到 n/ 2(向上取整)个长度为2或1的有序子序列;再两两归并…如此之重复,直至得到一个长度为n的有序序列为止。
-
动图演示:
-
java代码
/* * 归并排序 */ public static int[] MergeSort(int[] array) { if (array.length < 2) return array; int mid = array.length / 2; int[] left = Arrays.copyOfRange(array, 0, mid); int[] right = Arrays.copyOfRange(array, mid, array.length); return merge(MergeSort(left), MergeSort(right)); } /* * 归并排序——将两段排序好的数组结合成一个排序数组 */ public static int[] merge(int[] left, int[] right) { int[] result = new int[left.length + right.length]; for (int index = 0, i = 0, j = 0; index < result.length; index++) { if (i >= left.length) result[index] = right[j++]; else if (j >= right.length) result[index] = left[i++]; else if (left[i] > right[j]) result[index] = right[j++]; else result[index] = left[i++]; } return result; }
-
时间复杂度:T(n) = O(nlogn)
6. 快速排序(Quick Sort)
-
工作原理:首先任意选取一个数据(通常选取数组的第一个数)作为关键数据。然后将所有比它小的都放到它前面,把比它大的都放到它后面。
-
一趟快排的算法:
- 设置两个变量i,j。i= 0;j = len - 1.
- 以第一个数组元素作为关键数据,赋值给key,即 key - arr[0];
- 从j开始搜索(从后向前搜索,j- -),找到第一个小于 key 的值 arr[j],将arr[j] 和 arr[i] 的值交换
- 从i开始(从前往后搜索,i++),找到第一个大于key 的 arr[i],将 arr[i] 和 arr[j] 的值交换;
- 重复3 4 步,知道 i== j;
-
-
动图演示
-
java代码
/** * 快速排序方法 */ public static int[] QuickSort(int[] array, int start, int end) { if (array.length < 1 || start < 0 || end >= array.length || start > end) return null; int smallIndex = partition(array, start, end); if (smallIndex > start) QuickSort(array, start, smallIndex - 1); if (smallIndex < end) QuickSort(array, smallIndex + 1, end); return array; } /* * 快速排序算法——partition */ public static int partition(int[] array, int start, int end) { int pivot = (int) (start + Math.random() * (end - start + 1)); int smallIndex = start - 1; swap(array, pivot, end); for (int i = start; i <= end; i++) if (array[i] <= array[end]) { smallIndex++; if (i > smallIndex) swap(array, i, smallIndex); } return smallIndex; } /** * 交换数组内两个元素 */ public static void swap(int[] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; }
-
时间复杂度:T(n) = O(nlogn)
7. 堆排序(Heap Sort)
-
工作原理:在排序过程中,将待排序的序列看成一棵完全二叉树的顺序储存结构,利用完全二叉树中双亲结点和孩子结点之间的关系(子节点的值大于或者小于父节点的值),在当前无序序列中选择关键字最大(最小)的记录。
-
动图演示
-
java 代码
//声明全局变量,用于记录数组array的长度; static int len; /** * 堆排序算法 * * @param array * @return */ public static int[] HeapSort(int[] array) { len = array.length; if (len < 1) return array; //1.构建一个最大堆 buildMaxHeap(array); //2.循环将堆首位(最大值)与末位交换,然后在重新调整最大堆 while (len > 0) { swap(array, 0, len - 1); len--; adjustHeap(array, 0); } return array; } /** * 建立最大堆 * * @param array */ public static void buildMaxHeap(int[] array) { //从最后一个非叶子节点开始向上构造最大堆 for (int i = (len - 1) / 2; i >= 0; i--) { adjustHeap(array, i); } } /** * 调整使之成为最大堆 * * @param array * @param i */ public static void adjustHeap(int[] array, int i) { int maxIndex = i; //如果有左子树,且左子树大于父节点,则将最大指针指向左子树 if (i * 2 < len && array[i * 2] > array[maxIndex]) maxIndex = i * 2; //如果有右子树,且右子树大于父节点,则将最大指针指向右子树 if (i * 2 + 1 < len && array[i * 2 + 1] > array[maxIndex]) maxIndex = i * 2 + 1; //如果父节点不是最大值,则将父节点与最大值交换,并且递归调整与父节点交换的位置。 if (maxIndex != i) { swap(array, maxIndex, i); adjustHeap(array, maxIndex); } }
-
时间复杂度:T(n) = O(nlogn)
8. 总结
-
图片
-
视频
若视频连接失效 点击跳转百度网盘查看视频