10分钟学会七大排序(1)

一、插入排序

直接插入排序-原理:
整个区间被分为

  1. 有序区间
  2. 无序区间

每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入
具体实现的代码如下:

import java.util.Arrays;

public class SortDemo {
    public static void insertSort(int[] array){
    	//[0,bound)为拍好序的区间,[bound,size)为未排序的区间
        for (int bound = 1;bound < array.length;bound++){
            int tmp = array[bound];//下标为bound的元素为要插入的值,用tmp保存
            int cur = bound - 1;
            //对以排序号的区间从后往前遍历,为了让tmp也就是要插入的值找到合适的位置插入
            for(;cur >= 0;cur--){
                if(array[cur] > tmp){
                	//当前位置如果大于要插入的值,则需要将当前值向后搬运
                    array[cur + 1] = array[cur];//搬运
                }else {
                	//tmp找到合适的位置了
                    break;
                }
            }
            //下标为cur 的值<=tmp,所以cur+1为合适位置
            array[cur + 1] = tmp;
        }
    }

    public static void main(String[] args) {
    	//验证程序
        int[] array = {19,5,2,7,1,20,47,12,45};
        insertSort(array);
        System.out.println(Arrays.toString(array));
    }
}

[1, 2, 5, 7, 12, 19, 20, 45, 47]
排序是正确的


性能分析

时间复杂度
最好:O(N) – 数组有序
平均:O(N^2)
最坏:O(N^2) --数组逆序
  1. 稳定性:稳定
  2. 插入排序,初始数据越接近有序,时间效率越高。
  3. 空间复杂度:O(1)

二、希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,
所有记录在统一组内排好序。

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
	public static void shellSort(int[] array){
        int gap = array.length;
        while (gap > 1){
        	//这里gap>1都是预排序,为了让数组一步一步接近有序
            insertSortbyGap(array,gap);
            gap /= 2;
        }
        //最终排序
        insertSortbyGap(array,1);
    }
    public static void insertSortbyGap(int[] array,int gap){
    	//是直接插序的优化方法,但是有所差异
        for(int bound = gap;bound < array.length;bound++){
        	//边界可以从gap开始,因为分组了,前gap个元素,都是每一组的第一元素,后面进行插入
            int tmp = array[bound];//要插入的元素
            int cur = bound - gap;//为了找到tmp合适的插入位置,向前遍历
            for(;cur >= 0;cur -= gap ){
            	//预排序注意是--gap,
                if(array[cur] > tmp){
                	//搬运
                    array[cur + gap] = array[cur];
                }else {
                    break;
                }
            }
            array[cur + gap] = tmp;
        }
    }
    public static void main(String[] args) {
        int[] array = {9,5,2,7,6,2,8,1};
        shellSort(array);
        System.out.println(Arrays.toString(array));
    }

[1, 2, 2, 5, 6, 7, 8, 9]


性能分析:

时间复杂度
最好:O(N)–数组有序
平均:O(N^(4/3))
最坏:O(N^2)–比较难构造
  1. 空间复杂度:O(1)
  2. 稳定性:不稳定

三、选择排序

原理:
每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完 。

	public static void select(int[] arrays){
        for(int bound = 0;bound < arrays.length;bound++){
            int cur = bound + 1;//待排序的区间
            for (;cur<arrays.length;cur++){
                if(arrays[cur] < arrays[bound]){
                    swap(arrays,cur,bound);
                }
            }
        }
    }
    public static void swap(int[] array,int cur ,int bound){
        int tmp = array[cur];
        array[cur] = array[bound];
        array[bound] = tmp;
    }

选择排序就比较简单了,遍历这个数组,取到当前元素,当作擂台,嵌套循环(后面的待排序区间元素再依次打擂台,如果赢了就交换擂台的元素,嵌套循环结束后,待排序区间最小值站上擂台)。擂台后移,遍历结束也就完成排序。
性能分析:

  1. 时间复杂度:O(N^2),数据不敏感
  2. 空间复杂度:O(1),数据不敏感
  3. 不稳定

四、堆排序

思路如下:
堆排序思路和直接选择排序很像,每次取出一个最大值放到数组最后

  1. 先针对整个数组建堆
  2. 把堆顶元素放到数组最后
  3. 重新调整堆
public class SortDemo {
    public void creatHeap(int[] arrays){
    	//创建堆
        for(int i = (arrays.length - 1 - 1)/2; i >= 0;i--){
            //找到最后一个非叶子节点,从后往前遍历,向下调整
            shiftDown(arrays,arrays.length,i);
        }
    }
    public void swap(int[] arrays,int x,int y){
        int tmp = arrays[x];
        arrays[x] = arrays[y];
        arrays[y] = tmp;
    }
    public void shiftDown(int[] arrays,int size,int index){
    	//向下调整,三个参数,数组,调整的长度,下标
        int parent = index;
        int child = 2*parent + 1;
        while (child < size){
        	//千万注意,这里的长度用size,不用arrays.length!!!!!!!!!!!!!!
            if(child + 1 < size && arrays[child + 1] > arrays[child]){
                child = child + 1;
            }
            if(arrays[parent] < arrays[child]){
                swap(arrays,parent,child);
            }else {
                break;
            }
            //更新
            parent = child;
            child = 2*parent + 1;
        }
    }
    
    public void heapSort(int[] arrays){
        creatHeap(arrays);
        //将堆顶元素放最后,待排序区间向下调整
        for (int i = 0; i < arrays.length; i++) {
        	//[0,array.length - i) 待排序区间
        	//[array.length - i,array.length)已排序区间
            swap(arrays,0,arrays.length - i - 1);
            shiftDown(arrays,arrays.length - i - 1,0);
        }
    }
}

性能分析

  1. 时间复杂度:O(n*log(n)) 数据不敏感
  2. 空间复杂度:O(1) 数据不敏感
  3. 稳定性:不稳定
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值