十大排序算法JAVA实现

package project12_2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @auther 张弢
 * @create 2022-12-02 11:17
 */
public class Sort {
    public static void main(String[] args) {
        int[] arr={1,8,7,44,42,46,38,34,33,17,15,16,27,28,24};
//        Sort.bubbleSort(arr);//冒泡
//        Sort.selectSort(arr);//选择
//        Sort.insertSort(arr);//插入
//        Sort.shellSort(arr);//希尔
//        Sort.quickSort(arr,0,14);//快速
//        Sort.heapSort(arr);//堆
//        Sort.mergeSort(arr,0,arr.length-1);//归并
//        arr = Sort.CountSort(arr);//计数
//        Sort.bucketSort(arr);//桶
//        Sort.radixSort(arr);//基数

        traverse(arr);//数组遍历
    }

    //遍历方法
    public static void traverse(int[] arr){
        for (int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }
    //1.冒泡排序
    public static void bubbleSort(int[] arr){
        for (int i=0;i<arr.length;i++){
            for (int j=1;j<arr.length-i;j++){
                if (arr[j-1] > arr[j]){
                    int temp =arr[j-1];
                    arr[j-1]=arr[j];
                    arr[j]=temp;
                }
            }
        }
    }
    //2.选择排序
    public static void selectSort(int[] arr){
        for (int i=0;i<arr.length-1;i++){
            int minIndex=i;
            for (int j=i+1;j<arr.length;j++){
                if (arr[j]< arr[minIndex]){
                    minIndex=j;//每次循环找到值最小的下标
                }
            }
            int temp=arr[i];//每次循环结束后将最小值与数组第n(0-(length-1))位进行交换
            arr[i]=arr[minIndex];
            arr[minIndex]=temp;
        }
    }
    //3.插入排序
    public static void insertSort(int[] arr){
        for (int i=1;i<arr.length;i++){
            for (int j=i-1;j>=0;j--){
                if (arr[j+1] < arr[j]){
                    int temp =arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

    //4.希尔排序
    public static void shellSort(int[] arr){
        //初始化 划分增量
        int increment = arr.length;
        //每次循环减少增量,直到increment=1
        while (increment >1){
            //增量的多种取法之一
            increment = increment/3 + 1;
            //对每个按增量划分的分组分别进行 插入排序
            for (int i=increment;i< arr.length;i++){
                if (arr[i-increment] > arr[i]){
                    int temp = arr[i];//定义临时变量存放较小值
                    int j = i-increment;
                    //移动元素并寻找位置
                    while (j >= 0&& arr[j]>temp ){
                        arr[j+increment] = arr[j];//分组的后一个元素(较小值)被前一个元素(较大值)覆盖
                        j -= increment;//将前一个较小值与该组的前面的元素进行比较
                    }
                    //将较小值插入到正确的位置
                    arr[j+increment]= temp;
                }
            }
        }
    }

    //5.快速排序
    public static void quickSort(int [] arr,int left,int right){
        //数组空则直接返回结束
        if (left > right) return;
        //查找基准元素
        int mid= partition(arr,left,right);
        //递归进行排序
        quickSort(arr,left,mid-1);//将基准元素左边的区间进行快排
        quickSort(arr,mid+1,right);//将基准元素右边的区间进行快排
    }

    private static int partition(int[] arr, int left, int right) {
        //定义变量记录基准元素值
        int basis = arr[left];
        while (left < right){
            //左、右指针交替循环移动
            //右指针操作:right指针右向左扫描,扫描到数 《小于basis时,跳出循环,将小于基准的数赋值给相当于空余的基准位置赋值
            while (arr[right]>=basis&&left<right) right--;
                arr[left]=arr[right];
            //左指针操作:left指针左向右扫描,扫描到数 《大于basis时,跳出循环,将大于基准的数赋值给相当于空余的基准位置赋值
            while (arr[left]<=basis&&left<right) left++;
            arr[right]=arr[left];
        }
        arr[left]=basis;//或arr[right]=basis
        return left;
    }


    //6.堆排序
    public static void heapSort(int[] arr) {
        //旧数组构造==》符合大根堆的新数组
        heapInsert(arr);
        int size = arr.length;
        while (size > 1) {
            //固定最大值在数组的末索引,以构成有序
            swap(arr, 0, size - 1);
            size--;
            //固定最大值将剩余数继续构造大根堆
            heapify(arr, 0, size);
        }
    }

    //构造大根堆(通过新插入的数上升)
    public static void heapInsert(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            //当前插入的索引
            int currentIndex = i;
            //父结点索引
            int fatherIndex = (currentIndex - 1) / 2;
            //如果当前插入的值大于其父结点的值,则交换值,并且将索引指向父结点
            //然后继续和上面的父结点值比较,直到不大于父结点,则退出循环
            while (arr[currentIndex] > arr[fatherIndex]) {
                //交换当前结点与父结点的值
                swap(arr, currentIndex, fatherIndex);
                //当前索引变为其父索引
                currentIndex = fatherIndex;
                //重新计算新当前索引的新父索引,当前值与其父值比较判断是否进入循环继续交换
                //规则三:父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)
                fatherIndex = (currentIndex - 1) / 2;
            }
        }
    }
    //将剩余的数构造成大根堆(通过顶端的数下降)
    public static void heapify(int[] arr, int index, int size) {
        int left = 2 * index + 1;//规则一:寻找左孩子索引:2*i+1
        int right = 2 * index + 2;规则二:寻找左孩子索引:2*i+2
        //取左右孩子的最大值,并与其父节点的值比较判断是否交换值
        while (left < size) {
            int largestIndex;
            //判断孩子中较大的值的索引(要确保右孩子在size范围之内)
            if (arr[left] < arr[right] && right < size) {
                largestIndex = right;
            } else {
                largestIndex = left;
            }
            //比较父结点的值与孩子中较大的值,并确定最大值的索引
            if (arr[index] > arr[largestIndex]) largestIndex = index;
            //如果父结点索引是最大值的索引,那已经是大根堆了,则退出循环
            if (index == largestIndex) break;
            //父结点不是最大值,与孩子中较大的值交换
            swap(arr, largestIndex, index);
            //将索引指向孩子中较大的值的索引
            index = largestIndex;
            //重新计算交换之后的孩子的索引
            left = 2 * index + 1;
            right = 2 * index + 2;
        }

    }
    //交换数组中两个元素的值
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }


    //7.归并排序
    public static void mergeSort(int[] arr,int left,int right){
        if (left == right) return;//left、right相遇即分解完成
        int mid =(left+right)>>>1;//无符号右移一位,取中间值,相当于除2
        mergeSort(arr,left,mid);//将左侧继递归分解
        mergeSort(arr,mid+1,right);//将右侧递归分解
        merge(arr,left,mid,right);// --将左右递归合并--合并为有序,
    }

    private static void merge(int[] arr, int left, int mid, int right) {
        int s1= left;//左 归并段的开始位置
        int s2=mid+1;//右 归并段的开始位置
        //创建数组存放合并后的归并段
        int[] res =new int[right-left+1];//(3-0)+1=4:两归并段之和
        int i=0;//表示res数组的下标

        //比较s1、s2谁小谁入数组,将左、右归并段合并为有序归并段
        while (s1<=mid && s2<=right){//保证两个归并段都有数据
            if(arr[s1] <=arr [s2]){
                res[i++]=arr[s1++];
            }else {
                res[i++]=arr[s2++];
            }
        }
        //可能左右字段还存在未拷贝值,以下再次判断,有值则继续拷贝完成
        while (s1<=mid){
            res[i++]=arr[s1++];
        }
        while (s2<=right){
            res[i++]=arr[s2++];
        }
        //将res数组存的有序归并段放回原数组正确位置:加上left起始位置
        for (int j=0;j<res.length;j++){
            arr[j+left] = res[j];
        }
    }

    //8.计数排序
    public static int[] CountSort(int[] arr){
        //①找出原数组中的最大值
        int max=0;
        for (int i=0;i<arr.length;i++){
            if (arr[i]>max) max=arr[i];
        }

        //②初始化计数数组
        int[] count=new int[max+1];//长度为原数组最大值max+1
        //原数组的值转换为计数数组的下标,count数组元素值 随 遍历相同下标而自增+1
        for(int num:arr){
            count[num]++;
        }

        //③创建结果数组
        int[] result=new int[arr.length];
        //创建result数组的起始索引
        int index=0;
        //④遍历计数数组,将计数数组的索引下标 填充到 result数组中
        for (int i=0;i<count.length;i++){
            while (count[i]>0){
                result[index++]=i;
                count[i]--;
            }
        }
        return result;
    }

    //9.桶排序
    public static void bucketSort(int[] arr){
        //计算最大值、最小值
        int max=arr[0];
        int min=arr[0];
        for (int i=1;i<arr.length;i++){
            if (arr[i] < min) min=arr[i];
            if (arr[i] > max) max=arr[i];
        }
        //max-nin之差除数组长度,计算需桶数量
        int bucketNum=(max-min)/arr.length+1;//(46-1)/15再+1等于4个桶
        //创建桶,数量为bucketNum
        List<ArrayList<Integer>> buckets=new ArrayList(bucketNum);
        for (int i=0;i<bucketNum;i++){
            buckets.add(new ArrayList());
        }
        //将每个元素放入对应的桶中
        for (int i=0;i< arr.length;i++){
            int num=(arr[i]-min)/arr.length;//找元素对应的桶,元素越小,对应桶下标越小
            buckets.get(num).add(arr[i]);//放入对应的元素
        }
        //对桶中的元素进行排序
        for (int i=0;i<buckets.size();i++){
            Collections.sort(buckets.get(i));
        }
        //因为桶间已经有序,则逐一将桶中的元素赋值到原始数组
        for (int i=0,index=0;i<buckets.size();i++){
            for (int j=0;j<buckets.get(i).size();j++){
                arr[index++]=buckets.get(i).get(j);
            }
        }
    }

    //10.基数排序
    public static void radixSort(int[] arr){
        //取得数组中最大值
        int max=0;
        for (int i=0;i<arr.length;i++){
            if (arr[i] > max) max=arr[i];
        }
        //最大值是几位数
        int maxLength=(max+"").length();
        //定义一个二维数组模拟桶,每个桶即一维数组
        int[][] bucket=new int[10][arr.length];//10个桶,每个大小为数组长度
        //记录每个桶中实际存放的元素个数
        int[] bucketElementCounts=new int[10];
        //创建maxLength轮桶排序操作(对应个、十、百、...位的操作),就可将数组进行排序
        for (int i=0,n=1;i<maxLength;i++,n=n*10){//n=1:个位 n=10:十位 n=100:百位,通过变量n取出元素位数上的数
            for (int j=0;j<arr.length;j++){
                int digitOfElement = arr[j]/n%10;//针对每个元素第n位数进行处理
                bucket[digitOfElement][bucketElementCounts[digitOfElement]]=arr[j];//[桶][桶元素个数]=arr[j]
                bucketElementCounts[digitOfElement]++;//桶里元素个数+1
            }
            //按照桶顺序取出数据并放回原数组
            for (int k=0,index=0;k<bucket.length;k++){
                if (bucketElementCounts[k]!=0){
                    for (int l=0;l<bucketElementCounts[k];l++){
                        arr[index++] = bucket[k][l];
                    }
                }
                bucketElementCounts[k]=0;
            }
        }
    }


}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值