头秃的排序

 //冒泡排序  从小到大 从前向后
    //8, 7, 6, 5, 4    第1个---比较4次   2---3  3---2  4---1
    // 1, 2, 3, 4, 5
    //有序无序都需要比较4+3+2+1=10次   (n-1)+(n-2)+...+1=[n*(n-1)]/2---> O(n方)
    //无序时交换的次数=比较的次数*3  有序时交换的次数=0
    //内层循环每次结束都可以确定一个最值  由于 if (arr[j] > arr[j + 1])---》稳定
    public static int[] BubbleSort(int[] arr) {
        int length = arr.length;
        int temp;
        int compareCount = 0;
        int swapCount = 0;
        //比较 i-1 次  第1个---比较4次   2---3  3---2  4---1
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length - i - 1; j++) {
                compareCount++;
                if (arr[j] > arr[j + 1]) {
                    swapCount += 3;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        //最坏(逆序):比较了:10次  交换了:30次
        //最好(有序):比较了:10次  交换了:0次
        System.out.println("比较了:" + compareCount + "次  交换了:" + swapCount + "次");
        return arr;
    }
 //选择排序  假设第一个为最小值
    //8, 7, 6, 5, 4  1---4   2---3   3---2   4---1
    //1, 2, 3, 4, 5  1---4   2---3   3---4   4---1
    //最好最坏都比较4+3+2+1=10次   (n-1)+(n-2)+...+1=[n*(n-1)]/2---> O(n方)
    /*
       每次找到一个最值 交换3n次  和冒泡比较,交换的次数和长度有关,不在和比较的次数挂钩,
       所以即使无序,交换的次数会比冒泡少,但是有序时交换的次数会比冒泡多
     */
    //由于 if (arr[j] < min) ---》稳定
    public static int[] selectSort(int[] arr) {
        int compareCount = 0;
        int swapCount = 0;
        int min, index;
        int temp;
        for (int i = 0; i < arr.length; i++) {
            //默认第一个是最小值
            min = arr[i];
            index = i;
            //遍历确定真正的最小值并记录下标
            for (int j = i + 1; j < arr.length; j++) {
                compareCount++;
                if (arr[j] < min) {
                    min = arr[j];
                    index = j;
                }
            }
            //将最小值和arr[i]交换位置后  arr[i]及之前的有序  之后无序
            //将arr[i]之后的重复这个过程
            swapCount += 3;
            temp = arr[i];
            arr[i] = min;
            arr[index] = temp;
        }

        //最坏:比较了:10次  交换了:15次
        //最好:比较了:10次  交换了:15次
        System.out.println("比较了:" + compareCount + "次  交换了:" + swapCount + "次");
        return arr;
    }

    //插入排序
    //8, 7, 6, 5, 4  1=0     2---1   3---2   4---3  5---4
    //1, 2, 3, 4, 5  1=0     2---1   3---1   4---1  5---1
    //最好比较1+1+1+1=4次 O(n)  不需要交换
    //最坏比较1+2+...+(n-1)=[n*(n-1)]/2---> O(n方)  交换=比较的次数*3==10*3=30次
    /*和冒泡排序类似,在最好情况下, 插入排序只需要比较 不需要交换
                    在最坏情况下, 每次都要交换
      插入和冒泡比较类似的点在于:每次都能找到一个最值,将序列换分为有序和无序两个部分,冒泡排序向后比较,插入排序向前比较
                  区别是:冒泡排序每次的最值位置确定,不需要再改变  而插入需要
     */
    //由于(arr[j] < arr[j - 1])---》稳定
    //注: while (j > 0 &&arr[j] < arr[j - 1] )顺序不要变
    public static int[] insertSort(int[] arr) {
        int swapCount = 0;
        //i从0或者1开始都可以 比较次数只相差1  逻辑上默认第一个有序,从第二个开始和前面的比较即可
        for (int i = 1; i < arr.length; i++) {
            //默认第一个有序
            int j = i;
            //利用短路 j>0写在前面  依次和前面的元素比较交换
            while (j > 0 && arr[j] < arr[j - 1]) {
                int temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
                j--;
                swapCount += 3;
            }
        }
        //最坏:比较了:10次  交换了:30次
        //最好:比较了:4次  交换了:0次
        System.out.println("交换了:" + swapCount + "次");
        return arr;
    }

//希尔排序
    //8, 7, 6, 5, 4  87--65--4  6比较1次  4比较2次  5比较了1次 -》45-67-8  所以一共比较了4次 交换了4*3=12次
    //1, 2, 3, 4, 5  12--34--5  比较0次
    //希尔排序是一种有步长的插入排序 在元素数量较多的情况下,使整体大小分布有种趋向,目的是减少交换的次数
    //因为步长不断变化-》不稳定 例如:3 5*  6 1 5->3 1 5 5* 6->1 3 4 5* 6
    //注:(k - i) >= 0
    public static int[] shellSort(int[] arr) {
        int swapCount = 0;
        //每次划分的区间 i表示步长
        for (int i = arr.length / 2; i > 0; i = i / 2) {
            //每个区间有几个元素 就要进行几轮
            for (int j = 0; j < i; j++) {
                //然后是步长为i的插入排序
                for (int k = j + i; k < arr.length; k += i) {
                    while ((k - i) >= 0 && arr[k] < arr[k - i]) {
                        int temp = arr[k - i];
                        arr[k - i] = arr[k];
                        arr[k] = temp;
                        k = k - i;
                        swapCount += 3;
                    }
                }
            }
        }
        //最坏:交换了:12次
        //最好:交换了:0次
        System.out.println("交换了:" + swapCount + "次");
        return arr;
    }


    //快速排序
    //无序: 交换了:8次
    //有序:交换了:8次  有序的状态
    /*注:if (low > high) return; 8,7,6,5,4->4,7,6,5,8->...如果没有这个判断
       会出现right=-1 left=0 -》 while(left<right)不满足 -》 QuickSort(arr, 0, - 1);死循环 -》stackover
     */
    //arr[left] < key --》稳定
    public static void quickSort(int[] arr, int low, int high) {
        if (low > high) return;
        int left = low;
        int right = high;
        //第一个位置的元素作为基准元素
        int key = arr[left];
        while (left < right) {
            while (left < right && arr[right] > key) {
                //从右往左扫描,找到第一个比基准值小的元素
                right--;
            }
            //此时key=arr[left]  该处的值已经被key保存  且 表明基准值应该在arr[right]的右侧
            arr[left] = arr[right];
            swapCount++;
            while (left < right && arr[left] < key) {
                //从左往右扫描,找到第一个比基准值大的元素
                left++;
            }
            //表明基准值应该在arr[left]的左侧
            arr[right] = arr[left];
            swapCount++;
        }
        //left = right 表明第一次快排结束
        arr[left] = key;
        //对基准值左边的元素进行递归排序
        quickSort(arr, low, left - 1);
        //对基准值右边的元素进行递归排序。
        quickSort(arr, right + 1, high);
    }
 //归并排序
    public static void mergeSort(int[] arr, int left, int right) {
        //只有两个直接返回
        if (left >= right)
            return;
        //划分左侧
        int mid = (left + right) / 2;
        mergeSort(arr, left, mid);
        //划分右侧
        mergeSort(arr, mid + 1, right);
        //合并
        merge(arr, left, mid + 1, right);
        System.out.println("-------------");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    public static void merge(int[] arr, int leftstart, int rightstart, int rightend) {
        //678 1245
        int mid = rightstart - 1;
        int leftpos = leftstart;
        int rightpos = rightstart;
        /*if (rightend % 2 == 0) {//奇数个
            rightpos = mid + 1;
        } else {
            rightpos = mid;
        }*/
        //指向新的数组的起始位置
        int k = 0;
        //不要写成arr.length 数组复制的时候会出现越界异常
        int[] temp = new int[rightend - leftstart + 1];
        while (leftpos <= mid && rightpos <= rightend) {
            if (arr[leftpos] <= arr[rightpos]) {
                temp[k++] = arr[leftpos++];
            } else {
                temp[k++] = arr[rightpos];
                rightpos++;
            }
        }
        while (leftpos <= mid) {
            temp[k++] = arr[leftpos++];
        }
        while (rightpos <= rightend) {
            temp[k++] = arr[rightpos++];
        }
        //将temp里的元素复制到arr中保持修改
        for (int m = 0; m < temp.length; m++) {
            arr[leftstart + m] = temp[m];
        }
        for (int i = 0; i < temp.length; i++) {
            System.out.println(temp[i]);
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值