本篇博客给大家带来的是排序的知识点, 由于时间有限, 分两天来写, 上篇主要实现 前四种排序算法: 直接插入, 希尔, 选择, 堆排。
文章专栏: Java-数据结构
若有问题 评论区见
欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .
目录
王子公主请阅
1.排序的概念及应用
1.1 排序的概念
1.3 常见的排序算法
2. 常见排序算法的实现(默认排升序)
2.1 插入排序
2.1.1基本思想:
2.1.2 直接插入排序
直接插入排序具体操作:
2.1.3 希尔排序(缩小增量排序)
2.2 选择排序
2.2.1基本思想:
2.2.3 堆排序
王子公主请阅
1.排序的概念及应用
1.1 排序的概念
排序:所谓排序,就是使一串记录按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
1.3 常见的排序算法
2. 常见排序算法的实现(默认排升序)
2.1 插入排序
2.1.1基本思想:
直接插入排序是一种简单的插入排序法,其基本思想是:
如下模拟动图:
2.1.2 直接插入排序
直接插入排序具体操作:
第一步 理清思路:
当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,
1. 定义 tmp 保存 排序前 i 下标对应的值. for(i) 为 外循环, for(j) 为 内循环 , j = i -1 .
2. 遍历数组, 在内循环中, tmp 与 array[ j ] 进行比较,, 若是 tmp 小 则 [ j + 1] = [ j ];
若是 tmp 大 则 直接 break;
3. 在外循环中 将 最后 j + 1 位置的值 赋为 tmp值 , [ j + 1 ] = tmp;
第三步 画图理解 , 一目了然 :
第四步 代码实现:
/*** 时间复杂度:* 最好情况:数据完全有序的时候 1 2 3 4 5 :O(N)* 最坏情况:数据完全逆序的时候 5 4 3 2 1 :O(N^2)* 结论: 数据越有序,排序越快, * 场景: 现在有一组基本有序的数据,那么用哪个排序好点? - 直接插入排序.* 空间复杂度: O(1)* 稳定性: 稳定的排序* 一个本身就是稳定的排序 是可以实现为不稳定的排序的* 相反 一个本身就不稳定的排序 是不可以实现为稳定的排序的.** @param //直接插入排序*/public static void insertSort(int[] array) {for (int i = 1; i < array.length; i++) {int tmp = array[i];int j = i-1;for (; j >= 0; j--) {if(array[j] > tmp) { // >= 会变成不稳定的array[j+1] = array[j];}else {//array[j+1] = tmp; 执行了一次break;}}//当j=-1时,a[j+1]=tmp这条语句没被执行,所以再写一次array[j+1] = tmp; //执行了两次, 故把第一次屏蔽.}}
最后总结:
2.1.3 希尔排序(缩小增量排序)
希尔排序本质上 就是 在对直接插入排序做优化。
第一步 了解基本思想:
/*** 希尔排序** 时间复杂度:* n^1.3 - n^1.5* 空间复杂度: O(1)** 稳定性: 不稳定* @param //shell*/public static void shellSort(int[] array) {int gap = array.length;while(gap > 1) {gap /= 2;shell(array,gap);}//gap /= 2;不用写 因为gap=2或3时, gap/2 = 1.已经进行了直接插入排序.}private static void shell(int[] array,int gap) {for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i-gap;for (; j >= 0; j -= gap) {if(array[j] > tmp) {array[j+gap] = array[j];}else {break;}}array[j+gap] = tmp;}}
最后 希尔排序的特性总结:
2.2 选择排序
2.2.1基本思想:
/*** 选择排序** 时间复杂度:* 最好: O(N^2)* 最坏: O(N^2)*空间复杂度:O(N)** 稳定性: 不稳定** @param array*/public static void selectSort(int[] array) {for (int i = 0; i < array.length-1; i++) {int minIndex = i;for (int j = i+1; j < array.length; j++) {if(array[j] < array[minIndex]) {minIndex = j;}}swap(array,minIndex,i);}}public static void swap(int[] array,int i,int j) {int tmp = array[i];array[i] = array[j];array[j] = tmp;}
选择排序有 第二种写法, 反正都要遍历一遍数组, 不如把最大值和最小值都找出来, 最小的往最前放, 最大的往最后放.
第二种写法步骤:
1. 定义 left = 0, right = array.length-1, i = left + 1; minIndex = maxIndex = 0;
2. while( left < right )循环, i 在循环中, 遍历数组 找到最小元素下标 和 最大元素下标, 出循环 与 minIndex 和 maxIndex 交换.
3. 出循环后 考虑一个特殊情况 , 当 left = 0 下标 对应的值就是最大值时, 第二步出循环后的交换操作 将最大值交换到minIndex下标处了. 需要 再将 maxIndex 标记到最大值.
第二种写法代码实现:
public static void swap(int[] array,int i,int j) {int tmp = array[i];array[i] = array[j];array[j] = tmp;}//选择排序的第二种写法.public static void selectSort2(int[] array) {int left = 0;int right = array.length-1;while(left < right) {int minIndex = left;int maxIndex = left;for (int i = left; i <= right; i++) {if(array[i] < array[minIndex]) {minIndex = i;}if(array[i] > array[maxIndex]) {maxIndex = i;}}swap(array,left,minIndex);//有一种情况是maxIndex原本就在left位置上,上面的交换将最大值交换到minIndex下标处了.导致后续的排序不正确.if(maxIndex == left) {maxIndex = minIndex;}swap(array,right,maxIndex);left++;right--;}}
第四步 直接选择排序的特性总结:
2.2.3 堆排序
/***堆排序** 时间复杂度:O(N)+O(N*logN) 约等于 O(N*logN)** 如果都以最坏的情况来看,堆排序是目前来说最快的,希尔排序其次.* 假设希尔排序为O(N^1.3) 当N越大时,logN趋于不变所以,堆排序O(N*logN)要快一些.** 空间复杂度:O(1)* 稳定性:不稳定*/public static void heapSort(int[] array) {//建大堆createBigHeap(array);//O(N)int end = array.length-1;//O(N*logN)while(end > 0) {swap(array,0,end);shiftDown(array,0,end);end--;}}private static void createBigHeap(int[] array) {for (int parent = (array.length-1-1)/2; parent >= 0; parent--) {shiftDown(array,parent,array.length);}}private static void shiftDown(int[] array,int parent,int end) {int child = (parent*2)+1;while(child < end) {//保证右子树存在并且当右子树大的时候,child++来到右子树的下标.if(child+1 < end && array[child+1] > array[child]) {child++;}if(array[child] > array[parent]) {swap(array,child,parent);parent = child;child = parent*2+1;}else {//本身就是大根堆break;}}}
第三步 堆排序的特性总结: