1.基本概念
1.1排序的稳定性(重要)
两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳定性的排序算法。
(经验)如果当前这个排序,在排序的过程中没有发生跳跃式的交换,那么我们认为这个排序是稳定的排序,比如堆排,就是不稳定的。稳定的排序也可被实现为不稳定的排序,但不稳定的则不可以变成稳定的排序。
现实生活中的应用
2.常用排序总览
3.插入排序
3.1直接插入排序-原理
整个区间被分为
- 有序区间
- 无序区间
每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入
确定下标i,来遍历数组的元素,那么下标i从几开始呢,从数组的·1一位置开始,因为第一个数它肯定是有序的,再来一个下标j,j=i-1,再定义一个tmp,把当前下标的值(i下标)放到tmp中,如果j下标的值大于tmp中的值,将j下标的值放到i位置,j–,此时j<0,0位置没有元素,就将tmp放到0位置(这就成为了一个有序区间)这是第一次直接插入排序的过程,接下来我们上代码。
3.2实现
//稳定性:稳定
//时间复杂度:最坏:数据逆序o(n^2) 最好:数据有序可以达到o(n)
//所以对于直接插入排序,数据越有序越快
import java.util.Arrays;
public class dSort {
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 {
break;
}
}
array[j+1]=tmp;
}
}
public static void main(String[] args) {
int[] arr={
2,5,6,8,5};
insertSort(arr);
System.out.println(Arrays.toString(arr));
}
}
对于直接插入排序我们上面总结的结论,会经常遇见这样的问题:当前有一组待排序序列,但是这组待排序序列大部分是有序的请问下面那个排序最适合,对于这样的问题,不要犹豫,选直接插入排序。
另外:直接插入排序一般也会用在一些排序的优化上,例如快排,当数据越来越有序时,就可以进行更好的优化。
性能分析
4.希尔排序(了解)
说一句:如果是面试,你可以跳过希尔排序
4.1希尔排序-原理
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有记录分成个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取增量,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
- 希尔排序是对直接插入排序的优化
- 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
4.2实现
//稳定性:不稳定
//时间复杂度:最坏:o(n^2) 平均:o(n^1.3) 最坏:o(n^2)
//是对直接插入排序的优化
import java.util.Arrays;
public class shellSort {
public 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=j-gap){
if(array[j]>tmp){
array[j+gap]=array[j];
}else {
break;
}
}
array[j+gap]=tmp;
}
}
public static void shellSort(int[]array){
int []drr={
5,3,1};//增量数组,取值要求,没有除1之外的公因子,且最后一个增量值必须为1
for (int i = 0; i < drr.length; i++) {
shell(array,drr[i]);
}
}
public static void main(String[] args) {
int[] arr={
2,5,6,8,7,23,21,32,43,54,43,2,13,4,34,65,7,6,90};
shellSort(arr);
System.out.println(Arrays.toString(arr));
}
}
4.3性能分析
5.选择排序
5.1直接选择排序-原理
每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完 。
5.2实现
import java.util.Arrays;
public class selectSort {
public static void selectSort(int []array){
for (int i = 0; i < array.length-1; i++) {
int max=0;
for (int j = i+1; j <array.length;j++) {
if(array[i]>array[j]){
//交换
max=array[j];
array[j]=array[i];
array[i]=max;
}
}
}
}
public static void main(String[] args) {
int []arr={
2,3,5,7,8,9,13};
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
}
5.3性能分析
其实关于选择排序还有双向选择排序,但由于少用到,在此我们不再描写,感兴趣的朋友可以自行了解。
6.堆排序
6.1堆排序-原理
基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。
注意: 排升序要建大堆;排降序要建小堆。
关于具体实现过程以及原理请看此篇文章
6.2实现
6.21建大堆
/**
* 调整为大顶堆
* @param arr 待调整的数组
* @param parent 当前父节点的下标
* @param length 需要对多少个元素进行调整
*/
import java.util.Arrays;
public class heapSort {
//首先我们先完成大堆的构建
private static void adjustHeap(int[] arr, int parent, int length){
//临时保存父节点
int temp = arr[parent];
//左子节点的下标
int child = 2 * parent + 1;
//如果子节点的下标大于等于当前需要比较的元素个数,则结束循环
while(child < length){
//判断左子节点和右子节点的大小,若右边大,则把child定位到右边
if(child + 1 < length && arr[child] < arr[child + 1]){
child ++;
}
//若child大于父节点,则交换位置,否则退出循环
if(arr[child] > temp){
//父子节点交换位置
arr[parent] = arr[child];
//因为交换位置之后,不能保证当前的子节点是它子树的最大值,所以需要继续向下比较,
//把当前子节点设置为