常用的排序算法(Java实现)

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 交换排序:冒泡排序、快速排序
 * 选择排序:简单选择排序、堆排序
 * 插入排序:直接插入排序、希尔排序
 * 归并排序
 * 基数排序
 */

public class SortedNums {
    /**
     * 冒泡排序
     * 依次比较两个相邻的元素,如果顺序错误就将他们交换过来,直到没有相邻的元素需要交换。
     * @param nums
     */
    public void bubbleSorted(int[] nums) {
        if (nums.length < 2) {
            return;
        }
        int index = 0;
        //只需要遍历到倒数第二位
        for (int i = 0; i < nums.length - 1; i++) {
            //两两比较交换只需要length-1次
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j + 1]) {
                    index = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = index;
                }
            }
        }
    }
    /**
     * 快速排序:说白了就是给基准数据找出正确的索引位置。
     * O(nlogn)
     * @param nums
     * @param low
     * @param high
     */
    public void quickSorted(int[] nums,int low,int high){
        if (nums.length<2||nums==null){
            return;
        }
        if (low<high) {
            //获取基准数据的正确索引
            int index = getIndex(nums,low,high);
            //递归调用
            quickSorted(nums,low,index-1);
            quickSorted(nums,index+1,high);
        }
    }
    public int getIndex(int[] nums,int low,int high){
        //选取基准数据
        int num = nums[low];
        while (low<high){
            //当队尾元素大于基准数据时,向前挪动high指针
            while (low<high && nums[high]>num){
                high--;
            }
            //当队尾元素小于基准数据时,将high指针所指数据赋给low所指数据;若并不出现比基准数据小的,此时low=high,该语句不产生任何作用
            nums[low] = nums[high];
            while (low<high && nums[low]<num){
                low++;
            }
            nums[high]=nums[low];
        }
        //最终low=high就是基准数据的索引
        nums[low] = num;
        return low;
    }
    /**
     * 选择排序:在待排序的一组数据中,找出最大或最小的元素与第一个元素作交换,,然后在剩下的数中,再找最小或最大的元素与第二个交换位置,以此类推,
     * 直到第n-1和第n个元素交换,排序结束。
     * 不稳定
     * @param nums
     */
    public void selectSorted(int[] nums){
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j < nums.length; j++) {
                if (nums[j]<nums[i]){
                    int index= nums[i];
                    nums[i]=nums[j];
                    nums[j]=index;
                }
            }
        }
    }
    /**
     * 直接插入排序
     * 基本思想:将一条数据插入到已排好序的有序表中,从而得到一个新的,记录数量增1的有序表
     * @param nums
     */
    public void insertSorted(int[] nums) {
        if (nums.length < 2 || nums == null) {
            return;
        }
        int index = 0;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] < nums[i - 1]) {
                index = nums[i];
                for (int j = i; j >= 0; j--) {
                    if (j > 0 && nums[j - 1] > index) {
                        nums[j] = nums[j - 1];
                    } else {
                        nums[j] = index;
                        break;
                    }
                }
            }
        }
    }

    /**
     * 希尔排序:希尔排序是插入排序的一种“缩小增量排序”,是直接插入排序的一种更高效改进版,是非稳定排序。
     * 实现思路:将待排序的一组元素按一定间隔分为若干个序列,分别进行插入排序,在每轮排序中将间隔逐渐减小,直至为1,
     * 也就是最后一步是进行简单的插入排序
     * @param nums
     */
    public void shellInsert(int[] nums){
        int index =0;
        int len= nums.length;
        for (index = len/2; index > 0; index/=2){
            for (int i = index; i<len; i++){
                shellSorted(index,i,nums);
            }
        }
    }
    public void shellSorted(int index,int i,int[] nums){
        int temp = nums[i];
        int j;
        for (j = i-index; j>=0&&temp<nums[j]; j-=index){
            nums[j+index] = nums[j];
        }
        nums[j+index]=temp;
    }

    /**
     * 归并排序:归并是指将两个或两个以上的有序序列组合成一个新的有序序列。
     * 归并排序是指把无序的待排序序列递归分解成若干个长度大致相等的有序子序列,并把
     * 有序子序列合并为整体有序序列的过程。
     * @param nums 原数组
     * @param mid 拆分位置
     * @param L 左指针
     * @param R 右指针
     * @return
     */
    public void mSort(int[] nums,int mid,int L,int R){
        int[] temp = new int[R-L+1];//归并后的新数组
        int i = 0;//新数组开始索引
        int P1 = L;//第一个数组开始索引
        int P2 = mid+1;//第二个索引开始索引
        while (P1<=mid && P2<=R){//当第一个数组索引小于等于拆分位置而且第二个数组索引小于等于数组长度时,将其归并
            temp[i++] = nums[P1] < nums[P2] ? nums[P1++] : nums[P2++];
        }
        //当归并完成后,判断数组是否还有元素,并将其逐一添加
        while (P1<=mid){
            temp[i++] = nums[P1++];
        }
        while (P2<=R){
            temp[i++] = nums[P2++];
        }
        //最终把排序好的数组复制到原数组
        for (int j = 0; j < temp.length; j++) {
            nums[L+j] = temp[j];
        }
    }
    public void merge(int[] nums,int L,int R){
        if (L == R){
            return;
        }
        int mid = (L+R)/2;
        merge(nums, L, mid);
        merge(nums, mid+1, R);
        mSort(nums,mid,L,R);
    }
    public void mergeSort(int[] nums){
        merge(nums,0,nums.length-1);
    }

    /**
     * 基数排序:I一般情况下,将待排序的元素看成由m个关键字复合而成,每个关键字可能取r个值,则只需要从最低关键字起,根据关键字的值将其分配到
     * 对应的子序列,再按从小到大的顺序将个子序列一次首尾相接组成新的序列,重复m遍,最终得出的新序列就是完成排序的序列。
     * @param nums
     */
    public void basicSort(int[] nums){
        if (nums.length<2||nums==null){
            return;
        }
        int max = 0;
        int len = 0;
        //获取最大元素
        for (int i = 0; i < nums.length; i++) {
            max = max < nums[i] ? nums[i] : max;
        }
        //获取max的长度
        while (max>0){
            max/=10;
            len++;
        }
        //根据每个进位进行排序
        List<ArrayList<Integer>> basicList = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            ArrayList<Integer> queue = new ArrayList<>();
            basicList.add(queue);
        }
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < nums.length; j++) {
                //获取进位上的值
                int index = nums[j]%(int)Math.pow(10,i+1)/(int)Math.pow(10,i);
                basicList.get(index).add(nums[j]);
            }
            //开始收集
            int count = 0;
            for (int j = 0; j < basicList.size(); j++) {
                while (basicList.get(j).size()>0){
                    nums[count] = basicList.get(j).get(0);
                    basicList.get(j).remove(0);
                    count++;
                }
            }
        }

    }

    @Test
    public void test() {
        int[] arr = {55, 9, 4, 354, 87, 66, 1, 45, 3, 14, 86, 5};
        //quickSorted(arr,0,arr.length-1);
        //selectSorted(arr);
        //mergeSort(arr);
        basicSort(arr);
        System.out.println(Arrays.toString(arr));
    }

}
//堆排序
public static void sort(int[] arr){
        for (int i = arr.length/2-1; i >= 0; i--){
            adjust(arr, i, arr.length);
        }
        for (int j = arr.length - 1; j > 0; j--){
            int temp = arr[0];
            arr[0] = arr[j];
            arr[j] = temp;
            adjust(arr, 0, j);
        }
    }

    public static void adjust(int[] arr, int index, int len){
        int temp = arr[index];
        for (int i = index*2+1; i <len; i = i*2+1){
            if (i + 1 < len && arr[i] < arr[i+1]){
                i++;
            }
            if (temp < arr[i]){
                arr[index] = arr[i];
                index = i;
            }else {
                break;
            }
        }
        arr[index] = temp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值