各种排序算法代码

排序算法

一、分类

排序算法总结:
►插入排序:直接插入排序、折半插入排序、希尔排序
►交换排序:冒泡排序、快速排序
►选择排序:简单选择排序、堆排序
►归并排序
非比较类排序:
►基数排序
►计数排序、桶排序(要求排序的数据是有确定范围的整数)

二、比较

请添加图片描述

三、算法代码
//直接插入排序:第一个元素认为是有序的,然后向后一个个一个扩展将有序部分扩大
public void insertSort(int[] nums){
    int temp;
    //一个数默认有序
    for (int i=1;i<nums.length;i++){
        //记录当前需要插入的数据
        temp=nums[i];
        int j=i;
        //当前数据与前面的所有数据比较,前面数据比当前数据大的就往后移位
        while (j>0 && temp<nums[j-1]){
            nums[j]=nums[j-1];
            j--;
        }
        //比较结束,j的位置前面比当前数小,后面比当前数据大
        nums[j]=temp;
    }
}
// 折半插入排序:直接插入排序的改进,需要插入的数据与已排好序的数据的中间开始比较
public void halfInsertSort(int[] nums){
    int temp;
    //一个数默认有序
    for (int i=1;i<nums.length;i++){
        //记录当前需要插入的数据
        temp=nums[i];
        int j=i;
        int left=0,right=i-1;
        //取到等号:如果不取等号,left=right时的值未与temp进行比较,比较不完整
        while (left<=right){
            //不断折断,寻找中间位置
            int mid = (right+left)/2;
            if (temp<=nums[mid])
                //此时,nums[mid]的值比temp大,因此right从mid-1处重新开始计算
                right = mid-1;
            else
                //此时,nums[mid]的值比temp小,因此left从mid+1处重新开始计算
                left = mid+1;
        }
        for (;j>left;j--){
            nums[j]=nums[j-1];
        }
        //比较结束,j的位置前面比当前数小,后面比当前数据大
        nums[left]=temp;
    }
}
// 希尔排序:插入排序的再次改进
// 通过比较相距一定间隔的元素进行比较排序,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止
public void  shellKnuthSort(int[] nums){
    int temp,gap=nums.length/2;
    while (gap>0){
        for (int i=gap;i<nums.length;i++){
            temp = nums[i];
            //取前一个数
            int pre = i-gap;
            while (pre >= 0 && temp < nums[pre]){
                // 为什么取到[pre+gap]:进入循环表明temp比前一个间隔的数据小
                // 与插入排序相同的就是,希尔排序每个间隔、分组,从头开始排序,在这个分组中,前面部分已轮询的是已经排好序的
                nums[pre+gap]=nums[pre];
                pre = pre-gap;
            }
            // 此时的 pre+gap 处以及往后的数据是比temp大的,需要向后移
            nums[pre+gap] = temp;
        }
        gap/=2;
    }
}
// 冒泡排序:按顺序前后两个对比,大的在前就调换顺序
public void BubbleSort(int[] nums){
    int temp;
    for (int i = 0; i < nums.length; i++){
        //去除后面i个已经排好的元素,要 -1 不然会越界
       for (int j = 0;j<nums.length-i-1;j++){
           if (nums[j]>nums[j+1]){
               temp = nums[j];
               nums[j]=nums[j+1];
               nums[j+1]=temp;
           }
       }
    }
}
/* 一次快排的举例:
 23  46  0  8  11  18
temp=23
 18  46  0  8  11  18
 18  46  0  8  11  46
 18  11  0  8  11  46
 18  11  0  8  23  46

 10  46  0  8  11  18
temp=10
 8  46  0  8  11  18
 8  46  0 46  11  18
 8  0  0  46  11  18
 8  0  10 46  11  18*/
//快速排序:是对冒泡排序的一种改进
// 通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小
public void quickSort(int[] nums,int left,int right){
   if (left<right){
        // 经历一次快排,并得到基准数的位置索引
        int index = getIndex(nums,left,right);
        // 分块迭代,两边分别进行快排迭代
        quickSort(nums,left,index-1);
        quickSort(nums,index+1,right);
    }
}
public int getIndex(int[] nums,int left,int right) {
    //取基准数 1,2,2,3,0,3 temp=3
    int temp = nums[left];
    while (left<right){
        //从右边开始比,因为左边的数作为基准数了
        //取等号!!!
        // 为什么:如果数组中有相同的两个数,会陷入死循环,left 和 right 都无法再增减,而 left<right 一直为 true
        while (left<right && temp <= nums[right]){
            right--;
        }
        nums[left]=nums[right];
        //取等号!!!
        while (left<right && temp >= nums[left]){
            left++;
        }
        nums[right]=nums[left];
    }
    nums[left]=temp;
    return left;
}
//简单选择排序:不停的去寻找最大或最小的元素
public void selectionSort(int[] nums){
    for (int i=0;i<nums.length;i++){
        // 标记最小元素的位置索引
        int minIn = i;
        for (int j=i;j<nums.length;j++){
            if(nums[minIn]>nums[j]){
                minIn = j;
            }
        }
        int temp=nums[i];
        nums[i]=nums[minIn];
        nums[minIn]=temp;
    }
}
/*
* 堆排序:
*  什么是堆:
*   · 堆是一个完全二叉树
*   · 堆中每一个节点的值必须大于或者等于(小于或者等于)其左右子树的值。【大顶堆、小顶堆】
*
* 构建大顶堆或小顶堆,将最大数或者最小值与末尾的值互换后取出,重新构建大顶堆或小顶堆,重复。
* */
public void heapSort(int[] nums){
    /*数组构建堆:{2,6,3,0,9,7,1,2} → {9, 6, 7, 2, 2, 3, 1, 0}
    * 第一个数据为堆顶,因为是大顶堆,所以为本数组中的最大数
    * 第二三个数据分别是第一个数据的左右子树,6,7
    * 2,2 两个数是第二个数即6的左右子树;3,1 两个数是第三个数即7的左右子树
    * 以此类推
    * */
    maxheapify(nums,nums.length);
    for(int i=1;i<nums.length;i++){
        int temp=nums[0];
        nums[0]=nums[nums.length-i];
        nums[nums.length-i]=temp;
        maxheapify(nums,nums.length-i);
    }
}
private void maxheapify(int[] arr, int len) {
    int i;
    if(len%2==0){
        i=len/2;
    }else {
        i=(len-1)/2;
    }
    //要从尾部开始比较,不能从头部开始比较
    for(;i>0;i--){
        heapify(arr,i,len);
    }
}
private void heapify(int[] arr,int i, int len) {
    int left,right,lagest;
    left=2*i-1;
    right=2*i;
    lagest=i-1;
    if (left<len&&arr[lagest]<arr[left]){
        lagest=left;
    }
    if (right<len && arr[lagest]<arr[right]){
        lagest=right;
    }
    if (lagest!=i-1){
        int temp = arr[lagest];
        arr[lagest] = arr[i-1];
        arr[i-1] = temp;
        //因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
        heapify(arr,i, len);
    }

}
// 归并排序:归并法,先使子序列有序,再将两个子序列合并使其有序,直至整个序列有序
public int[] mergeSort(int[] nums){
    if (nums.length <= 1) return nums;
    int mid = nums.length / 2;
    //分为左右两部分,左闭右开
    int[] left = Arrays.copyOfRange(nums, 0, mid);
    int[] right = Arrays.copyOfRange(nums, mid, nums.length);
    //递归
    return merge(mergeSort(left), mergeSort(right));
}
//合并
public 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 (right[j] < left[i])
            result[index] = right[j++];
            //左数组当前元素小,添加左数组元素
        else
            result[index] = left[i++];
    }
    return result;
}
/*
* 基数排序 vs 计数排序 vs 桶排序
* 这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
*   基数排序:根据键值的每位数字来分配桶;
*           先以个位数的大小来对数据进行排序,接着以十位数的大小来多数进行排序,接着以百位数的大小……
*   计数排序:每个桶只存储单一键值;(适合于最大值和最小值的差值不是不是很大的排序)
*           把数组元素作为数组的下标,然后用一个临时数组统计该元素出现的次数,例如 temp[i] = m, 表示
*           元素 i 一共出现了 m 次。最后再把临时数组统计的数据从小到大汇总起来,此时汇总起来是数据是有序的。
*   桶排序:每个桶存储一定范围的数值;
*          桶排序就是把最大值和最小值之间的数进行瓜分,例如分成  10 个区间,10个区间对应10个桶,
*          我们把各元素放到对应区间的桶中去,再对每个桶中的数进行排序,可以采用归并排序,也可以采
*          用快速排序之类的。
* */
// 基数排序
public void countSort(int[] nums){
    int max=nums[0],n=nums.length;
    // 找出最大值
    for (int i =1;i<n;i++){
        if (max<nums[i])
            max=nums[i];
    }
    //计算最大值为几位数
    int num = 1;
    while (max / 10 > 0) {
        num++;
        max = max / 10;
    }
    // 创建10个桶
    ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(10);
    //初始化桶
    for (int i = 0; i < 10; i++) {
        bucketList.add(new LinkedList<Integer>());
    }
    // 进行每一趟的排序,从个位数开始排
    for (int i = 1; i <= num; i++) {
        for (int j = 0; j < n; j++) {
            // 获取每个数最后第 i 位是数组
            int radio = (nums[j] / (int)Math.pow(10,i-1)) % 10;
            //放进对应的桶里
            bucketList.get(radio).add(nums[j]);
        }
        //合并放回原数组
        int k = 0;
        for (int j = 0; j < 10; j++) {
            for (Integer t : bucketList.get(j)) {
                nums[k++] = t;
            }
            //取出来合并了之后把桶清光数据
            bucketList.get(j).clear();
        }
    }
}
// 我的下意识想法
public void mysort(int[] nums){
    int temp;
     for (int i=0;i<nums.length;i++){
        for (int j=i+1;j<nums.length;j++){
            if (nums[i]>nums[j]){
                temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值