0
点赞
收藏
分享

微信扫一扫

数据结构与算法-----常见排序算法

笙烛 2022-02-26 阅读 120

一、冒泡排序

int score[] = {67,100,50,99,87,89,90,75};

boolean flag = false;
/**
 * 1、length方法用于获取数组的长度。
 * 2、而length()用于获取String字符串中字符的个数。
 * 第一轮计算的是需要几趟排序才能排完
 */
for (int i=0;i<score.length-1;i++){
    //第二轮这个计算的是一趟排序内需要比较几次才能比较完
    for (int j=0;j<score.length-1-i;j++){
        if (score[j] > score[j+1]){
            flag = true;
            int number = score[j];
            score[j] = score[j+1];
            score[j+1] = number;
        }
    }
    if (!flag){
        //说明一次一次比较都没有发生,已经排好序了
        break;
    } else{
        //说明至少排过一次序,重置标志才能有效
        flag = false;
    }
}

二、选择排序

int score[] = {67,100,50,99,87,89,90,75};
    selectSort(score);
    System.out.println(Arrays.toString(score));
}
private static void selectSort(int[] arr) {
    //一共有几轮,比当前数组的长度少一轮
    for (int i = 0; i < arr.length - 1; i++) {
        /**
         * 用于暂存数据,两个功能
         * 一、比如:假设第一个是最小的,则记录第一个下标以及数据,实际第一个可能不是最小的
         * 等到循环比较以后,第一个就变成最小的,则进行第二个数比较,取得最小值。
         * 可以说是记录比较到了第几位
         * 二、将暂存那个比假设的那个值要大的数,用于后续进行交换
         */
        int midIndex = i;
        int mid = arr[i];
        //已经假设第一个是最小的,所以从第二个开始,与第一个进行比较
        for (int j = i + 1; j < arr.length ; j++) {
            //如果想按从大到小排序,可以把这里变成<
            if (mid > arr[j]) {
                //将比假设值要大的那个元素以及元素下标付给中间变量进行存储
                midIndex = j;
                mid = arr[j];
            }
        }
        //等于的话,就相当于没有交换,本身就是最小的
        if (midIndex != i) {
            /**这下面两部不能反过来,否则会出错,因为原先大的元素已经放入mid这个中间值里面了
             * 原先位置已经空出来了,所以要把arr[i]先放过去,然后再发mid中间值放入arr[i]中,
             */
            //将原来假设小的放到后面,因为假设小的不是最小的,这里为什么用midIndex,就是因为那个被置换的小标是j是在里面的循环里面,只能先付给外面的才行
            arr[midIndex] = arr[i];
            //将比假设的值小的元素,付给原来假设小的元素的那个位置
            arr[i] = mid;
        }
    }
}

三、插入排序

int[] scop = {3, 1, 5, 4, 9, 7, 6, 8};
    insertSort(scop);
    System.out.println("拍好后:"+ Arrays.toString(scop));
}

private static void insertSort(int[] arr) {
    //循环几次,注意最后一位也要进行比较
    for (int i = 1; i < arr.length; i++) {
        //第一位是标志位,所以从第二位开始
        int insertValue = arr[i];
        //这里的意思就是,取前一位的下标,如果是从第二位开始,那就是第一位的下标也就是0
        int insertIndex = i - 1;

        /**
         * 1、insertIndex >= 0:保证给insertValue这个数找插入的位置不越界
         * 2、insertValue < arr[insertIndex]:如果标志位,也就是前一位比后一位,也就是要插入的哪一位要小,就不用插入了
         *
         */
        while (insertIndex >= 0 && insertValue < arr[insertIndex]) {
            arr[insertIndex + 1] = arr[insertIndex];
            insertIndex--;
        }
        /**
         * 假如标志位是第一位,那么从第二位开始,
         * insertValue 就是第二位,
         * insertIndex 就是第一位的坐标
         * arr[insertIndex + 1]其实就是第二位,相当于把第二位的值再付给他自己
         */
        arr[insertIndex + 1] = insertValue;
        System.out.println("每一轮排序:"+ Arrays.toString(arr));
    }
}

四、快速排序

int[] scop = {3, 1, 5, 4, 9, 7, 6, 8};
    quickSort(scop,0,scop.length-1);
    System.out.println(Arrays.toString(scop));
}

private static void quickSort(int[] arr, int left, int right) {

    int l = left;
    int r = right;
    int mid = arr[(left + right) / 2];
    int temp =0;

    //比mid小的放到左边,比mid大的放到右边
    while (l < r) {

        //从最左边找,比中间值小的,一直知道比中间值大的就退出
        while (arr[l] < mid) {
            l +=1;
        }

        //从最右边找,找到比mid小的,就退出
        while(arr[r] > mid){
            r -= 1;
        }

        //这里说明左边已经是全部小于等于中间值,右边已经全部是大于等于中间值
        if (l>= r){
            break;
        }

        //找到了,那就要开始交换了
        temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;


        /**
         * 其实就是mid这个值左右两边,刚好有两个和mid相等的数
         * 然后这里只是在mid左边与mid相等时,去移动右边的下标,
         * 然后右边的值和mid相等时,移动左边的下标而已
         */
        //如果交换后,发现这个arr[l] == mid这个值,r--,前移
        if (arr[l] == mid){
            r -= 1;
        }
        //如果交换后,发现这个arr[r] == mid这个值,l++,后移
        if (arr[r] == mid){
            l += 1;
        }
    }
    //如果l == r,必须l++,r--,否则会出现栈溢出
    if(l ==r ){
        l+=1;
        r-=1;
    }

    //向左递归
    if (left<r){
        quickSort(arr, left, r);
    }
    //向右递归
    if (right>l){
        quickSort(arr, l, right);
    }
}

五、分治算法

 

/**
 * 归并排序
 */
public class test6 {
    public static void main(String[] args) {

        int[] scop = {3, 1, 5, 4, 9, 7, 6, 8};
        int[] temp = new int[scop.length];
        mergeSort(scop, 0, scop.length - 1, temp);
        System.out.println(Arrays.toString(scop));
    }

    //分加合
    public static void mergeSort(int[] arr, int left, int right, int[] temp) {
        /**
         * 这里用了递归
         * (1)第一次:执行第一个 mergeSort   执行前判断:left=0,right=7 
         * 左边:3, 1, 5, 4    右边:9, 7, 6, 8  这是一次循环
         *  进行第二次:执行第一个 mergeSort  数组是:3, 1, 5, 4   left=0,right=3
         *  左边:3, 1    右边:5, 4
         * 第三次:执行第一个 mergeSort  数组是:3, 1    left=0,right=1 
         * 左边:3      右边  1
         * 第四次前:数组是:3  left=0,right=0
         * 然后left < right不满足,跳出第四次循环的,
         * 执行第三次循环中第二个mergeSort,右边数组为5, 4   执行前判断:mid 为 0 ,left=mid+1 = 1,right=1 不满足left < right
         * 进入merge(),数组虽然是[3, 1, 5, 4, 9, 7, 6, 8],但是他只比较,3, 1,因为这是第三次循环中的元素----3,1  之后会比较5,4(注意如果第二个mergeSort里面还有递归,还会执行第一个
         * mergeSort方法)
         * 如此一致递归
         * 
         */
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid, temp);
            mergeSort(arr, mid + 1, right, temp);
            merge(arr, left, mid, right, temp);
        }

    }

    /**
     * @param arr   排序的原始数组
     * @param left  左边有序序列的初始索引。比如:分成两份后,这个就是左边那份的第一个索引
     * @param mid   中间索引
     * @param right 右边索引
     * @param temp  做中转的数组
     */
    public static void merge(int[] arr, int left, int mid, int right, int[] temp) {

        int i = left; //初始化i为左边有序序列的初始索引
        int j = mid + 1; //初始化j为右边有序序列的初始索引
        int t = 0; //这向temp数组的当前索引
        /**
         * 一、
         * 先把左右两边有序的数组按照规则填充到temp数组中,
         * 直到有一边处理完为止
         */
        while (i <= mid && j <= right) {
            //如果左边的有序序列的当前元素,小于右边有序序列的当前元素,就将左边的当前元素转移到temp数组中,
            // 然后左边数组下边加一,temp数组下边向后移一位
            if (arr[i] <= arr[j]) {
                temp[t] = arr[i];
                t += 1;
                i += 1;
            } else {//反之将右边的放到temp当中
                temp[t] = arr[j];
                t += 1;
                j += 1;
            }
        }
        /**
         * 二、
         * 如果比完后还有剩下的,就将剩下的全部移动到temp数组当中
         */
        while (i <= mid) {//左边还有剩
            temp[t] = arr[i];
            t += 1;
            i += 1;
        }
        while (j <= right) {//右边还有剩
            temp[t] = arr[j];
            t += 1;
            j += 1;
        }
        /**
         * 三、
         * 将temp数组元素拷贝到arr当中
         * 注意不是每次都拷贝
         *
         * 就是合并的几个步骤
         */
        t = 0;
        int tempLeft = left;
        //第一次合并 tempLeft = 0,right = 1     第二次:tempLeft = 2,right = 3   第三次:tempLeft = 0,right = 3
        //最后一次合并:tempLeft = 0,right = 7
        System.out.println("tempLeft=" + tempLeft + ",right = " + right);
        while (tempLeft <= right) {
            arr[tempLeft] = temp[t];
            t += 1;
            tempLeft += 1;
        }

    }
}

六、二分查找

/**
 * 二分查找,只能用于有序的数组当中,
 */
public class test7 {
    public static void main(String[] args) {
        int[] scop = {1, 2, 3, 4, 5, 6, 7, 8};
        System.out.println(binarySelect(scop,0,scop.length-1,5));

    }
    public static int binarySelect(int[] arr, int left, int right, int targ) {

        //当左边大于右边时,退出递归,这是第一种情况
        if (left > right) {
            return -1;
        }
        int mid = (left + right) / 2;
        //当目标值刚好和中间值相等时,就说明找到了,退出递归
        int midValue = arr[mid];

        if (targ > midValue) {
            //这里会一直递归,知道找到和中间值相等,或者找不到的情况下,才会退出递归
            return binarySelect(arr, mid + 1, right, targ);
        } else if (targ < midValue){
            return binarySelect(arr, 0, mid - 1, targ);
        }else {
            //返回找到的中间值
            return mid;
        }
    }
}
举报

相关推荐

0 条评论