八大排序算法-代码实现-Java

本文深入讲解了九种经典排序算法的实现与原理,包括直接插入排序、希尔排序、冒泡排序、快速排序、直接选择排序、堆排序、归并排序、基数排序,以及一个比较工具。每种算法都配有详细的步骤解析和代码示例,帮助读者理解和掌握各种排序算法的特点与应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   // 直接插入排序
    public static void insertSort(int[] nums){
        /*
        * 思想:将一个元素插入一个已经排过序的数组
       *实例:假设数组的第二个元素为要插入的元素,第一个元素为已经排过序的数组
        * */


        // 依次遍历插入
        for(int i=1;i<nums.length;i++){
            // 说明需要插入(这里和已排序数组的最大值进行比较,小于最大值,说明需要插入)
            if(nums[i] < nums[i-1]){

                int temp = nums[i];

                // 确定要插入的位置(先记录索引,不要见一个就交换一个)
                int j ;
                for( j=i-1;j>=0&& nums[j]>temp;j--){
                    // 依次往后移动
                    nums[j+1] = nums[j];
                }
                // 此时nums[j] <=temp, 将temp交换至+1处
                nums[j+1] = temp;
            }
        }
    }


    // 希尔排序
    public static void shellSort(int[] nums){

        /*
        *思想:先局部有序,再总体有序
        * 具体思路:
        * 1.通过一个增量(如nums.length/2),来进行分组,(0->d)的元素的倍数为一组
        * 2. 分组后,通过通过直接插入排序进行排序
        * */

        // 确定初始增量
        int d = nums.length/2;

        // 通过whle 不断改变增量
        while (true){

            // 循环结束条件
            if(d == 1){
                break;
            }
            // 增量递减
            d=d/2;

            // 确定每组的初始值,遍历每组
            for(int x = 0;x<d;x++){

                // ---------采用直接插入排序进行排序------------
                for(int i= x+d;i<nums.length;i=i+d){ // 每组的第二个元素开始,因为直接插入排序的思想

                    // 确定可以去插入
                    if(nums[i]<nums[i-d]){
                        int temp = nums[i];

                        // 将位置向右移
                        int j;
                        for(j = i-d;j>=0 && nums[j]>temp;j=j-d){
                            nums[j+d] = nums[j]; // 需要把nums[i] 站住
                        }

                        // 经过循环后,nums[j]<=temp,故调换的位置在nums[j+d]
                        nums[j+d] = temp;
                    }
                }
            }


        }
    }

    //冒泡排序
    public static void bubbleSort(int[] nums){
        /*
        * 思想:依次比较相邻的两个元素,一轮下来会产生一个最大(或最小的元素)
        *
        * */

        for(int i=0;i<nums.length-1;i++){ // n-1轮
            for(int j = 0;j<nums.length-1-i;j++) // -i是因为i轮后,会有i个元素的有序数组在后面
            {
                if(nums[j] >nums[j+1]){
                    int temp = nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = temp;
                }
            }
        }
    }

    //快速排序
    /**
     *
     * @param nums 排序的数组
     * @param left 数组的初始位置
     * @param right 数组的末尾位置
     */
    public static void quickSort(int[] nums,int left,int right){
        /*
        * 思想:
        * 1.以第一个元素为基准(其他数也行)
        * 2. 首先从右侧指针开始,定位到一个比基准数小的元素的位置
        * 3.然后从左侧开始,定位到一个比基准数大的元素的位置
        * 4.交换这两个位置
        * 5.然后继续移动,直到左右指针相等,这时,left == right
        * 6.交换基准数宇nums[left]or nums[right]的位置
        * 7.这时以left or right 位置为中心,分成两个数组,依次使用  递归 ,快排 排序
        * */

        // 递归结束条件
        if(left>right){
            return;
        }

        // 首先记录 left 与right的位置
        int begin = left ;
        int end = right;

        // 基准数
        int baseNum = nums[left];

        // 移动左右指针,交换位置  ,最后交换基准数

        while (begin<end){
            // 移动右侧指针,定位到比baseNum 小的元素的位置

            while (nums[end] >=baseNum  && begin<end){
                end--;
            }

            //移动左侧指针,定位到比baseNum大的元素的位置
            while (nums[begin]<=baseNum && begin<end){
                begin++;
            }

            // 满足交换条件
            if(begin<end){

                int temp = nums[begin];
                nums[begin] = nums[end];
                nums[end] = temp;
            }
        }


        // 交换基准数与nums[begin or end]位置
       int tmp =nums[left];
       nums[left] =nums[end];
       nums[end] = tmp;

        // 左侧子数组递归,快排
        quickSort(nums,left,end-1);
        // 右侧子数组递归,快排
        quickSort(nums,end+1,right);

    }

    // 直接选择排序、

    public static void selectSort(int[] nums){
        /*
        * 思想:就是我们最常用的排序思想,选择一个元素与生于的所有元素进行比较
        * */

        for(int i = 0;i<nums.length-1;i++){
            // 记录最小值的索引位置,这样就不用每交换一次
            int minIdx = i;
            for(int j =i+1;j<nums.length;j++){


                // 小的放前面
                if(nums[j]<nums[minIdx]){
                    minIdx = j;
                }
            }
            swap(nums,minIdx,i);
        }
    }

    // 堆排序
    public static void heapSort(int[] nums){

        /*
        * 思想: 参考:https://blog.youkuaiyun.com/u013384984/article/details/79496052
        * 1.构建大顶堆(len/2  个非叶子节点开始,依次递减调整,直至到0
        * 2.交换堆顶和堆尾元素
        * 3.除交换的堆尾元素外,将剩余元素重新调整为大顶堆
        * */

        int len = nums.length;
        // 初始化堆
        for(int x = len/2;x>=0;x--){
            heapAdjust(nums,x,len);
        }


        // 交换元素,重新调整len-1个数组的堆
        for (int i = nums.length-1;i>=0;i--){

            // 交换元素
            swap(nums,0,i);
            len--;
            // 重新调整 剩下元素为大顶推
            heapAdjust(nums,0,len);
        }

    }
    // 调整堆
    public static void heapAdjust(int[] nums,int i,int len){
        /*
        * 思想:调整时,只沿着改变的那个子节点的方向,进行向下调整
        * 原因:因为两个没改变的节点的方向,是最大堆了,不需要再调整了
        * */

        // 左右子节点
        int leftNo = 2*i+1;
        int rightNo = 2*i+2;

        // 先构建这三个节点的最大堆
        // 默认当前父节点,在这三个节点中,值为最大的那个
        int largest  = i;

        // 左子节点与父节点先比较
        if(leftNo<len &&nums[largest] < nums[leftNo]){
            largest = leftNo;
        }
        // 再右节点与largest 节点比较
        if(rightNo<len && nums[largest] < nums[rightNo]){
            largest =rightNo;
        }
        // 如果改变了,则交换位置
        if(largest != i){
            swap(nums,i,largest);

            // 递归往深层调整(也可采用循环的方式(k,k+1),我才用的是递归的方式)
            heapAdjust(nums,largest,len);
        }



    }

    // 归并排序

    /**
     *
     * @param nums
     * @param low 数组首位
     * @param high 数组末位
     */
    public static void mergeSort(int[] nums,int low,int high){
        /*
        * 思想:通过递归的方法把数组分为两个有序数列,然后合并,
        * 递归前进时进行划分,退回时进行合并
        *
        * 当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序
        * */
        if(low<high){
            // 数组分割成两个左右数组
            int mid = (low+high)/2; // 这里时low+high 不是high-low
            // 左子序递归排序
            mergeSort(nums,low,mid);
            // 右子序递归排序
            mergeSort(nums,mid+1,high);
            // 合并两个有序数组
            merge(nums,low,mid+1,high);
        }




    }
    // 合并两个有序数组
    public static void merge(int[] nums,int low,int mid,int high){

        int i = low;
        int j = mid;
        // 创建一个临时数组(需要第三个数组)
        int[] tempArray = new int[high-low+1];
        int k= 0;

        while (i<mid && j<=high){
            if(nums[i]>nums[j]){
                // 先放入临时数组
                tempArray[k++] = nums[j++]; // 放入小的
            }else {
                tempArray[k++] = nums[i++];
            }
        }

        // 如果有数组没有放完
        while (i<mid){
            tempArray[k++] =nums[i++];
        }
        while (j<=high){
            tempArray[k++] = nums[j++];
        }

        // 将tempArray copy到nums low 至 high 处

        for(int m = 0;m<k;m++){
             nums[low++] = tempArray[m];
        }

    }


    // 基数排序

    /**
     *
     * @param nums
     * @param d 数组最大元素的位数
     */
    public static void radixSort(int[] nums,int d){
        /*
        * 思想:
        * 1.依次将数组元素的个位数至最高位数,放到标号0-9的桶子里,每一轮要将
        * 放好的元素,重新串起来,再开始下一轮位数的放置
        *
        * */

        // 依次遍历各位,放置后,重新串起来开启下一轮
        int m = 1; // 记录循环到哪一位了(如十位、百位)
        int n =1; // 用于控制获取哪一位的数
        while (m<d){
            // 创建桶子
            int[][] barrel = new int[10][nums.length];
            // 创建 记录每个桶子所含元素的计数器
            int[] counter = new int[10];

            // 开始依据位数元素,放置梗

            // 记录每个序号里桶子里元素的个数
            int[] cur_num = new int[10];
            for(int i=0;i<nums.length;i++){
                // 获取当前位上的 数
                int single_num = (nums[i]/n)%10;

                // 放入带有序号的桶子(对于位数相等的,因为上一位已经排序了,故相同号的桶,
                // 小的数是放在数组左边的,故下面串起来时,就直接是从小到大的
                barrel[single_num][cur_num[single_num]] = nums[i];   // 这里理解一下
                cur_num[single_num]++;
            }

            // 把元素串一起
            int idx =0;
            for(int p=0;p<10;p++){
                if(cur_num[p]>0){
                    for(int q=0;q<cur_num[p];q++){
                        nums[idx++] = barrel[p][q];// 
                    }
                }
            }



            // 开启下一轮
            m++;
            n=n*10;

        }



    }











    // 比较工具
    /**
     *
     * @param nums 数组
     * @param i 索引i
     * @param j 索引j
     */
    public static void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i]  = nums[j];
        nums[j] = temp;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值