排序最全的知识总结:基础概念+思路+图解+代码(详细注释)

排序: 使一串记录按照其中的某个或者某些关键字的大小,递增或递减的排列起来的操作。(在以下文章中,通常指排升序)
说明: 排序是基于比较的排序,从小到大的排序,这篇博客详解了七个排序,但并不代表排序只有七种排法。
稳定性: 两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳定性的排序算法。【也可理解为发生跳跃式变换(即不在相邻的数之间变换)的就是不稳定的】
时间复杂度: 两个并列的时间复杂度相加(取较大的那个),两个嵌套的时间复杂度相乘。
空间复杂度: 若没有增加额外的空间,那么空间复杂度就是O(1)。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第1张图片

排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第2张图片

一、插入排序

1、直接插入排序

(1)思路: 直接插入排序数组的第一个元素默认是有序的,所以要从1号下标开始比较,先把1号下标的元素放进临时空间,将临时空间的元素与有序数组的最后一个元素进行比较,如果有序数组中的元素大,就把该元素放进空着的位置,再把临时空间的元素放进刚刚有序数组中移动了元素的位置;如果有序数组的最后一个元素比临时空间的元素小,就继续把临时空间的元素放回原来的位置,然后i++,一直循环直到无序数组的最后一个元素排好序。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第3张图片
(2)时间复杂度: 最坏情况:O(n²);最好情况(有序情况):O(n)—— 越有序越快
(3)空间复杂度: O(1)
(4)是否稳定: if(array[j]>temp) 稳定;if(array[j]>=temp) 不稳定——>总结:稳定
如果一个排序是稳定的排序,那么它可以变为不稳定的排序;但是如果一个排序本身就是不稳定的,那么它是不可能变成一个稳定的排序的。如果是稳定的排序,那么在比较的过程中没有跳跃式的变换

import java.util.Arrays;
public class Sort {
    public static void insertSort(int[] array){
        for(int i=1;i<array.length;i++){
            // 有序区间:[0,i)
            // 无序区间:[i,array.length)
            int temp=array[i];//先将无序区间的第一个数先放进临时空间temp里
            int j;
            for(j=i-1;j>=0;j--){
                if(array[j]>temp){//然后将temp与有序空间的最后一个数进行比较
                    array[j+1]=array[j];//若temp小于有序空间当前下标的数,就将有序空间的下标往前移,直到找到使temp找到合适的位置插进去
                }else{
                    break;//必须有的,不然当temp需要插入到有序数组的中间时,这层循环结束不了
                }
            }
            array[j+1]=temp;//当j<0时跳出循环执行这一步或者若temp小于有序空间当前下标的数,就将temp赋值给j+1下标对应的位置
        }
    }
    public static void main(String[] args) {
        int[] array={10,5,8,4,1,9};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环
        insertSort(array);
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第4张图片
折半插入排序(了解):
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第5张图片

//折半插入排序
public static void bsInsertSort(int[] array) { 
	for (int i = 1; i < array.length; i++) { 
		int v = array[i]; 
		int left = 0; 
		int right = i; 
		// [left, right) 
		// 需要考虑稳定性 
		while (left < right) { 
			int m = (left + right) / 2; 
			if (v >= array[m]) { 
			left = m + 1; 
			} else { 
			right = m; 
		} 
	}
	// 搬移 
	for (int j = i; j > left; j--) { 
	array[j] = array[j - 1]; 
	}
	array[left] = v; 
	} 
}

2、希尔排序

希尔排序法又称缩小增量法,是对直接插入排序的优化。
(1)基本思想: 先选定一个数,把待排序文件中所有记录分成组,对每一组的数据进行排序,然后重复上述分组和排序的工作,直到所有的数据都排完序。(采用分组的思想,组内进行直接插入排序)
【如下图所示:对第一行的图进行一次循环解释:根据直接插入排序的思想,同一种颜色所对应的数据为同一组数据,拿红色线对应的数据来说,这一组里面对应的间隔是5,所以12对应的是j下标,8对应的是i下标,然后将8放进temp里,再使temp与j下标对应的数据进行比较,比较大的放在后面的位置,即把12放在i下标所对应的位置,然后j-5发现小于0,就把8放在j+5所对应的下标的位置(即12原先所处的位置),然后i++,i下标到了33那个位置,j=i-5,所以j下标在5那个位置,把33放进temp,使temp和j下标所对应的数据比较,谁大谁放在靠后的位置。。。一直到循环结束,这是结束了将数据分为5组的一次循环,接下来将数据分别分成3组和1组的进行比较,发现会很快的使数据有序。】
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第6张图片
(2)时间复杂度: 最坏情况:O(n²);最好情况:O(n)
(3)空间复杂度: O(1)
(4)是否稳定: 不稳定(发生跳跃式变换)

import java.util.Arrays;
public class Sort {
    public static void shellSort(int[] array){//用这个函数使数组里的数据分组排序
        int[] drr={5,3,1};
        for(int i=0;i<drr.length;i++) {
            shell(array, drr[i]);//将该drr数组传进shell排序函数中,第一次分5组,第二次分3组,第三次分1组
        }
    }
    //该排序的详解在直接插入排序的讲解里就有,不再赘述,过程一样一样的!
    public static void shell(int[] array,int gap){//这里的排序函数就是直接插入排序,但是需注意i和j开始的地方(见上图),j减的时候应该是j=j-gap
        for(int i=gap;i<array.length;i++){
            int temp=array[i];
            int j;
            for(j=i-gap;j>=0;j-=gap){
                if(array[j]>temp){
                    array[j+gap]=array[j];//这里发生跳跃式变换
                }else{
                    break;
                }
            }
            array[j+gap]=temp;
        }
    }
    //其实结果就相当于,在shellSort那个函数里,将怎么分组用数组表示出来,
    // 然后使真正的排序算法在分组的循环中将每种分组形式都过一遍,然后顺序就排出来了,真神奇呢!
    public static void main(String[] args) {
        int[] array={12,5,9,34,6,8,33,56,89,0,7,4,22,55,77};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环
        shellSort(array);
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第7张图片

二、选择排序

1、直接选择排序

(1)基本原理:每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第8张图片
(2)时间复杂度: O(n²)
(3)空间复杂度: O(1)
(4)是否稳定: 不稳定(发生跳跃式变换)

import java.util.Arrays;
public class Sort {
	public static void selectSort(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 static void main(String[] args) {
        int[] array={12,4,5,10,3};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环
        selectSort(array);
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第9张图片
2、堆排序

(1)思路: 从小到大排序应该建立的是大根堆(若是建立小根堆,只知道最顶端元素是最小的,其余的元素无法知道其排序),最顶端的元素肯定是最大的,每次将顶端元素和下标为end的元素(先开始使最后一位元素的下标为end)交换,交换完之后要向下调整,使end–,再使第二(三、四、五、、、)次调整后的堆顶元素与end下标所对应的位置进行交换,一直循环,直至end=0,这时候的堆就是从小到大的排序了
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第10张图片
(2)时间复杂度: O(nlog2ⁿ)
(3)空间复杂度: O(1)
(4)是否稳定: 不稳定(发生跳跃式变换)

import java.util.Arrays;
public class Sort {
//堆排序:先建堆,将建成的堆调整为大根堆,使堆顶元素与下标为end的元素(从堆的最后一个元素走起)进行交换,交换完end--,再调整,直至end<0
    public static void createHeap(int[] array){//建堆
        for(int i=(array.length-1-1)/2;i>=0;i--){//从最后一棵子树开始调整,i表示的是父结点
            adjustDown(array,i,array.length);
        }
    }
    //root:每棵子树开始的位置;len:结束位置
    public static void adjustDown(int[] array,int root,int len){//向下调整
        int parent=root;
        int child=2*parent+1;
        while(child<len){//最起码有左孩子
            if(child+1<len&&array[child]<array[child+1]){//确保有右孩子并且右孩子>左孩子,所以需要调整的孩子结点要变成右孩子
                child++;
            }
            if(array[child]>array[parent]){
                int temp=array[child];
                array[child]=array[parent];
                array[parent]=temp;
                parent=child;
                child=2*parent+1;
            }else{
                break;
            }
        }
    }
    public static void heapSort(int[] array){
        createHeap(array);
        int end=array.length-1;
        while(end>0){//根结点和end下标对应的结点进行交换
            int temp=array[0];
            array[0]=array[end];
            array[end]=temp;
            adjustDown(array,0,end);
            end--;
        }
    }
    public static void main(String[] args) {
        int[] array={27,15,19,18,28,34,65,49,25,37};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环      
        heapSort(array);//堆排序
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第11张图片

三、交换排序

1、冒泡排序

(1)思路: 使相邻的两个数进行比较,谁大谁放在后面。每一趟比较完最大的就在最后。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第12张图片
注意: 弄个语句判断是否发生交换,是因为可以减少最外层的循环,万一数组本来就是有序的,就不用非得等到最外层循环结束再结束,就可以直接return,提高效率。
(2)时间复杂度: O(n²),优化之后(已有序)可能达到O(n)
(3)空间复杂度: O(1)
(4)是否稳定: 稳定(未发生跳跃式变换)

import java.util.Arrays;
public class Sort {
    public static void bubbleSort(int[] array){
        for(int i=0;i<array.length-1;i++){//i表示趟数
            boolean flg=false;//趟数优化需要
            for(int j=0;j<array.length-1-i;j++){//区间优化
                if(array[j]>array[j+1]){
                    int temp=array[j];
                    array[j]=array[j+1];
                    array[j+1]=temp;
                    flg=true;//搁这儿弄个语句判断是否发生交换
                    //若发生交换那flg=true,若没发生交换,则这个if语句都不用进来,
                    // 待循环结束就直接到了if(flg==false)这里了,能到这里说明数组已经有序
                }
            }
            if(flg==false){
                return;
            }
        }
    }
    public static void main(String[] args) {
        int[] array={7,4,8,2,6};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环
        bubbleSort(array);
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第13张图片
2、快速排序

(1)思路: 从待排序区间,选一个数作为基准值,遍历整个待排序区间,比这个基准值小的放在这个数的左边,比这个基准值大的放到这个数的右边。然后再缩小范围,继续选一个基准值,把大的放在基准值右边,小的放在基准值左边,直到数组有序。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第14张图片
(2)时间复杂度: 最好情况:O(nlog2ⁿ);最坏情况(逆序):O(n²)
快排要快,那么每次划分序列的时候,如果都可以均匀的进行划分,那么效率最好。
(3)空间复杂度: 最好情况:O(log2ⁿ);最坏情况:O(n)
(4)是否稳定: 不稳定(发生跳跃式变换)

递归:

import java.util.Arrays;
public class Sort {
	public static void insert_Sort(int[] array,int start,int end){//优化方法一需要调用的直接插入排序算法
        for(int i=start+1;i<=end;i++){
            int temp=array[i];//先将无序区间的第一个数先放进临时空间temp里
            int j;
            for(j=i-1;j>=start;j--){
                if(array[j]>temp){//然后将temp与有序空间的最后一个数进行比较
                    array[j+1]=array[j];//若temp小于有序空间当前下标的数,就将有序空间的下标往前移,直到找到使temp找到合适的位置插进去
                }else{
                    break;//必须有的,不然当temp需要插入到有序数组的中间时,这层循环结束不了
                }
            }
            array[j+1]=temp;//当j<0时跳出循环执行这一步或者若temp小于有序空间当前下标的数,就将temp赋值给j+1下标对应的位置
        }
    }
    public static void three_num_mid(int[] array,int left,int right){//优化方法二需要调用的函数。三数取中,提高效率
        //array[mid]<=array[left]<=array[right];
        int mid=(left+right)/2;
        if(array[left]>array[right]){
            int temp=array[left];
            array[left]=array[right];
            array[right]=temp;
        }
        if(array[mid]>array[left]){
            int temp=array[left];
            array[left]=array[mid];
            array[mid]=temp;
        }
        if(array[mid]>array[right]){
            int temp=array[mid];
            array[mid]=array[right];
            array[right]=temp;
        }
    }
    public static int partition(int[] array,int low,int high){//找基准值
        int temp=array[low];
        while(low<high){
            while((low<high)&&(array[high]>temp)){
                high--;
            }
            array[low]=array[high];
            while((low<high)&&(array[low]<temp)){
                low++;
            }
            array[high]=array[low];
        }
        array[low]=temp;
        return low;
    }
    public static void quick(int[] array,int left,int right){//规定每次排序的是哪些范围
        if(left>right){
            return;
        }
        //优化方式一:当待排序序列的数据个数小于等于100(随便给的范围)的时候,用直接插入排序
        if(right-left+1<100){//当数据趋于有序时,这一步优化可以减小时间复杂度
            insert_Sort(array,left,right);//insert_Sort()这个函数只应用于这里
            return;
        }
        //优化方法二:
        //three_num_mid(array,left,right);//三数取中,three_num_mid()这个函数只应用到这里

        int par=partition(array,left,right);
        quick(array,left,par-1);
        quick(array,par+1,right);
    }
    public static void quickSort(int[] array){
        quick(array,0,array.length-1);
    }
    public static void main(String[] args) {
        int[] array={6,1,2,7,9,3,4,5,10,8};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环       
        quickSort(array);//快速排序
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

非递归:

思路: 先找到基准值,然后将基准值的左右的最前和最后的下标都入栈,比如第一次找到的基准值是下标为5的元素,那么就该把下标0,4,6,9入栈,然后找数对,依次弹出两个栈顶元素,弹出的这两个元素构成一个区间,然后在这个区间里继续找基准值(找基准值的过程实际也是排序的过程),当栈不为空时就重复以上的操作,直到所有的元素都有序(这个时候栈应该为空)。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第15张图片
写程序的顺序:建栈,将left和right赋初值,找第一次的基准值,将基准值左右两侧的最前和最后下标入栈,当栈不为空时,一次出两个栈顶元素,分别使其成为right和left,再找一次基准值,再将基准值的左右的最前和最后下标入栈,直到栈为空。

import java.util.Arrays;
import java.util.Stack;
public class Sort {
	public static int partition(int[] array,int low,int high){//找基准值
        int temp=array[low];
        while(low<high){
            while((low<high)&&(array[high]>temp)){
                high--;
            }
            array[low]=array[high];
            while((low<high)&&(array[low]<temp)){
                low++;
            }
            array[high]=array[low];
        }
        array[low]=temp;
        return low;
    }
    //写程序的顺序:建栈,将left和right赋初值,找第一次的基准值,将基准值左右两侧的最前和最后下标入栈,
    //当栈不为空时,一次出两个栈顶元素,分别使其成为right和left,再找一次基准值,再将基准值的左右的最前和最后下标入栈,直到栈为空
    public static void quickSort(int[] array){
        Stack<Integer> stack=new Stack<>();//存放数对
        int left=0;
        int right=array.length-1;
        int par = partition(array, left, right);
        if (par > left + 1) {//将基准值左边下标入栈
            stack.push(left);
            stack.push(par-1);
        }
        if (par < right - 1) {//将基准值右边下标入栈
            stack.push(par+1);
            stack.push(right);
        }
        while(!stack.empty()) {
            right=stack.pop();//将left和right重新赋值
            left=stack.pop();
            par = partition(array, left, right);//继续找基准值
            if (par > left + 1) {//将基准值左边下标入栈
                stack.push(left);
                stack.push(par-1);
            }
            if (par < right - 1) {//将基准值右边下标入栈
                stack.push(par+1);
                stack.push(right);
            }
        }
    }
    public static void main(String[] args) {
        int[] array={6,1,2,7,9,3,4,5,10,8};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环 
        quickSort(array);//快速排序
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果: (递归+非递归)
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第16张图片

四、归并排序

1、归并排序

(1)思路: 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第17张图片
(2)时间复杂度: O(nlog2ⁿ)
(3)空间复杂度: O(n)
(4)是否稳定: 稳定(可实现为一个不稳定的排序)。在合并时只是进入到另外一个数组里了,并没有发生跳跃式交换

递归:

import java.util.Arrays;
public class Sort {
	public static void mergeSortInternal(int[] array,int low,int high){//拆分
        if(low>=high){
            return;
        }
        //分解
        int mid=(low+high)>>>1;
        mergeSortInternal(array,low,mid);//将一系列数拆分成一个一个的
        mergeSortInternal(array,mid+1,high);
        //合并
        merge(array,low,mid,high);
    }
    public static void merge(int[] array,int low,int mid,int high){//归并两个有序段
        int s1=low;
        int s2=mid+1;
        int len=high-low+1;//ret的数组长度
        int i=0;//用来表示ret的下标
        int[] ret=new int[len];//用来存放归并后的数组
        while(s1<=mid && s2<=high){//在规定的范围里,依次判断s1和s2的大小,然后再拿出来放在ret数组里
            if(array[s1]<=array[s2]){
                ret[i++]=array[s1++];
            }else{
                ret[i++]=array[s2++];
            }
        }
        while(s1<=mid){//若s2中没有元素,s1中还有元素那么将s1中剩余的元素拿出来
            ret[i++]=array[s1++];
        }
        while(s2<=high){//若s1中没有元素,s2中还有元素那么将s2中剩余的元素拿出来
            ret[i++]=array[s2++];
        }
        for(int j=0;j<ret.length;j++){//这里需要注意!!!,不能按原位置从ret复制到array
            array[j+low]=ret[j];
        }
    }
    public static void mergeSort(int[] array){
        mergeSortInternal(array,0,array.length-1);
    }
    public static void main(String[] args) {
        int[] array={10,6,7,1,3,9,4,2};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环
        mergeSort(array);//归并排序
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第18张图片
非递归:

思路: 如图。总的来说就是使两个归并段 (先使每个归并段只有一个元素,然后2倍的增长) 进行比较,谁小,谁先拿出来放在结果数组里,然后不断扩展归并段的规模,直到数据全部进入一个归并段,其中有很多细节需要考虑,比如每个归并段的范围、临界条件、只剩一个归并段怎么办、各个变量的初值和结束位置、某个需要判断的地方需要不需要=等等,认认真真的思考!!!【只是图和文字看不懂的话就结合代码,代码的注释部分有些地方说的很详细。】
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第19张图片

import java.util.Arrays;
public class Sort {
	public static void mergeSort(int[] array){
        for(int gap=1;gap<array.length;gap*=2){//规定每组划分多少个数据
            mergeNor(array,gap);
        }
    }
    public static void mergeNor(int[] array,int gap){
        int[] ret=new int[array.length];//存放结果的数组
        int k=0;//ret的下标
        int s1=0;   //先确定4个位置
        int e1=s1+gap-1;
        int s2=e1+1;
        int e2=s2+gap-1 < array.length ? s2+gap-1 : array.length-1;//e2不能越界,最大只能等于array.length-1
        while(s2<array.length){//1、够两个归并段
            //2、对应的s1位置和s2位置进行比较,谁小先把谁拿出来
            while(s1<=e1 && s2<=e2) {
                if (array[s1] <= array[s2]) {
                    ret[k++] = array[s1++];
                }else {
                    ret[k++] = array[s2++];
                }
            }
            //3、在比较完之后,肯定先有一个先走完,判断是谁没走完,需要把剩下的数据拷贝到结果数组当中
            /*if(s1>e1 && s2<=e2){//这一段和下面的两个while看似是对等的,实际上是不对的,因为不能保证还有剩余元素的归并段只剩下一个元素,用while就可以解决这个问题
                ret[k++]=array[s2++];
            }
            if(s2>e2 && s1<=e1){
                ret[k++]=array[s1++];
            }
            */
            while(s1<=e1){
                ret[k++]=array[s1++];
            }
            while(s2<=e2){
                ret[k++]=array[s2++];
            }

            //4、接着确定新的s1 e1 s2 e2
            s1=e2+1;
            e1=s1+gap-1;
            s2=e1+1;
            e2=s2+gap-1 < array.length ? s2+gap-1 : array.length-1;//e2不能越界,最大只能等于array.length-1
        }
        //5、还需判断是否有另外的单一的归并段,若是有另外的单一的归并段,则需将它拷贝到ret的后面
        //有两种情况:一种是这个单一的归并段有两个及以上的元素;另一种是这个单一的归并段只有一个元素,
        //所以判断条件不能使s1<=e1,因为e1都可能越界,所以只要s1
        while(s1<array.length){
            ret[k++]=array[s1++];
        }
        for(int i=0;i<array.length;i++){//然后将元素从ret数组搬到array数组
            array[i]=ret[i];
        }
    }
    public static void main(String[] args) {
        int[] array={15,2,35,6,23,11,5};
        long start=System.currentTimeMillis();
        System.out.println("排序前:"+Arrays.toString(array));//这样打印数组不用写循环      
        mergeSort(array);//归并排序
        System.out.println("排序后:"+Arrays.toString(array));
        long end=System.currentTimeMillis();
        System.out.println("所用时间:"+(end-start));
    }
}

执行结果:
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第20张图片

海量数据排序问题:

外部排序:排序过程需要在磁盘等外部存储进行的排序
前提:内存只有 1G,需要排序的数据有 100G
因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序

  1. 先把文件切分成 200 份,每个 512 M
  2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
  3. 进行 200 路归并,同时对 200 份有序文件做归并过程,最终结果就有序了

排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第21张图片

基于非比较的排序:

计数排序

基数排序

桶排序
排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第22张图片排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第23张图片

排序最全的知识总结:基础概念+思路+图解+代码(详细注释)_第24张图片

你可能感兴趣的:(Java,课程学习,数据结构,java,排序算法,快速排序)