排序问题(Java)

排序问题,总的分为两类:比较排序和非比较排序。


1、冒泡排序

对于要排序的数组,从第一位开始从前往后比较相邻两个数字,若前者大,则交换两数字位置,然后比较位向右移动一位。第1轮从前到后的比较将使得最大的数字 冒泡 到最后,此时可以说一个数字已经被排序。每一轮的比较将使得当前未排序数字中的最大者被排序,未排序数字总数减 1。第 arr.length - 1arr.length−1 轮结束后排序完成。

public class bubbleSort {
    public static void main(String[] args) {
        int arr[] = {1,5,8,3,2};
        System.out.println("排序结果如下:");
        bubbleSort bubbleman = new bubbleSort();
        arr = bubbleman.bubble(arr);

        for (int i = 0; i < arr.length; i++){
            System.out.print(arr[i]+" ");
        }
    }

    public int[] bubble(int[] arr){
        if (arr.length < 2)
            return arr;
        // n - 1轮次执行,当前 n - 1 个元素排好后,最后一个元素无需执行,故i < arr.length - 1
        for(int i = 0; i < arr.length - 1; i++){
            boolean swapped = false;
            for (int j = 0; j < arr.length - 1 - i; j++){
                if (arr[j] > arr[j+1]){
                    swap(arr, j,j+1); //改变数组相邻位置的顺序
                    swapped = true;
                }
            }

            //如果这一轮没有任何交换则说明:数组已经完全排序,退出大循环
            if (swapped == false) break;
        }
        return arr;
    }

    //该方法不传递值,只是改变了数组的顺序
    private void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

2、选择排序

每一次从待排序的数组里找到最小值(最大值)的下标,然后将最小值(最大值)跟待排序数组的第一个进行交换,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。反复的进行这样的过程直到待排序的数组全部有序。 选择排序分为:单元选择排序(min或max)、双元选择排序(一轮遍历同时找出min和max)。

public class SelectSort {
    public static void main(String[] args) {
        int arr[] = {4,6,2,1,7,9,5,8,3};
        System.out.println("排序结果如下:");
        SelectSort sortway = new SelectSort();
        arr = sortway.selectSort(arr);

        for (int i = 0; i < arr.length; i++){
            System.out.print(arr[i]+" ");
        }
    }

    public int[] selectSort(int[] arr){
        if (arr.length < 2)
            return arr;
        for (int i = 0; i < arr.length; i++){
            int minindex = i;
            for (int j = minindex; j < arr.length; j++){
                if (arr[minindex] > arr[j]){
                    minindex = j;
                }
            }
            // 然后进行交换,每一轮确定minindex指定的位置
            swap(arr, i , minindex);
        }
        return arr;
    }

    //该方法不传递值,只是改变了数组的顺序
    private void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

 3、插入排序

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。 插入排序也分为:简单插入排序、折半插入排序。

// 简单插入排序
public class InsertSort {
    public static void main(String[] args) {
        int arr[] = {4,6,2,1,7,9,5,8,3};
        System.out.println("排序结果如下:");
        InsertSort sortway = new InsertSort();
        arr = sortway.insertSort(arr);

        for (int i = 0; i < arr.length; i++){
            System.out.print(arr[i]+" ");
        }
    }

    public int[] insertSort(int[] arr){
        if (arr.length < 2)
            return arr;
        for (int i = 1; i < arr.length; i++){
            // 从数组的第二个值开始处理
            int target = arr[i];  //保存目标值
            int j;
            for (j = i; j>0 && arr[j-1] > target; j--){ // 递减的一个迭代
                // 把大于target的数往后移动,最后不大于target的数就空出来j
                arr[j] = arr[j-1];  //该元素右移
            }
            arr[j] = target;
        }
        return arr;
    }
}

4、希尔排序

希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。算法思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

import java.util.Arrays;

public class ShellSort {

    public static void main(String[] args) {
        int[] arr={49,38,65,97,76,13,27,49,78,34};
        shellSort(arr);
    }

    // static是静态修饰符,有全局的意思
    public static void shellSort(int[] arr){
        int count = 0; //表示第几轮
        for (int gap = arr.length/2; gap>=1; gap = gap/2){ //步长
            count++;
            // 分组
            for (int i = gap; i < arr.length; i++){
                for (int j = i - gap; j >= 0; j = j - gap){
                    if (arr[j] > arr[j + gap]){
                        // 然后进行交换,每一轮确定minindex指定的位置
                        swap(arr, j , j + gap);
                    }
                }
            }
            System.out.println("第"+count+"轮的排序结果");
            System.out.println(Arrays.toString(arr)); //打印
        }
    }
    //该方法不传递值,只是改变了数组的顺序
    static void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

5、归并排序

归并排序的核心思想是分治、递归。先将待排序的数组不断拆分,直到拆分到区间里只剩下一个元素的时候。不能再拆分的时候。这个时候我们再想办法合并两个有序的数组,得到长度更长的有序数组。当前合并好的有序数组为下一轮得到更长的有序数组做好了准备。一层一层的合并回去,直到整个数组有序。

                       

import java.util.Arrays;

public class MergeSort {

    public static void main(String[] args) {
        int [] array = {12, 56, 2, 8, 18, 35, 29};
        System.out.println(Arrays.toString(array));
        mergeSort(array, 0, array.length-1);
        System.out.println(Arrays.toString(array));
    }

    public static int[] mergeSort(int[] array, int low, int high){
         int mid = (low + high)/2;  //记录中间值
         if (low < high){
             //分解:对数组进行递归(每一个数组分为两部分)
             mergeSort(array, low, mid);        //左边归并排序
             mergeSort(array, mid+1, high); //右边归并排序

             merge(array, low, mid, high);  //合并(两个有序的数组)
         }
         return array;
    }

    public static void merge(int[] array, int low, int mid, int high){
        int s1 = low;   //第一个归并段的开始
        int s2 = mid+1; //第二个归并段的开始
        int[] ret = new int[high-low+1];
        int i = 0; //表示数组下标

        while(s1 <= mid && s2 <= high){  //越界检测
            if (array[s1] <= array[s2]){ // 对比大小,调整顺序
                ret[i++] = array[s1++];
            }else {
                ret[i++] = array[s2++];
            }
        }
        while(s1<=mid){ //s1和s2如果还有剩余的
            ret[i++] = array[s1++];
        }
        while(s2<=high){
            ret[i++] = array[s2++];
        }
        //把ret数组的值,拷贝到array中
        for (int j = 0; j < ret.length; j++){
            array[j+low] = ret[j]; //不能乱放。从low开始
//            System.out.println(ret[j]);  // debug
        }
//        System.out.println("========");
    }
}

6、快速排序

(1)通过从数组中选择一个中心元素将数组划分成两个子数组,在划分数组时,将比中心元素小的元素放在左子数组,将比中心元素大的元素放在右子数组。
(2)左子数组和右子数组也使用相同的方法进行划分,这个过程一直持续到每个子数组都包含一个元素为止。
(3)最后,将元素组合在一起以形成排序的数组。

通俗:先把数组中的一个数当作基准数,一般会把数组中最左边的数当作基准数。然后从两边进行检索。先从右边检索比基准数小的;再从左边检索比基准数大的。如果检索到了,就停下来,然后交换这两个元素(基准数和相遇位置的数交换),然后再继续检索。

import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int [] array = {12, 56, 2, 8, 18, 35, 29};
        System.out.println(Arrays.toString(array));
        quickSort(array, 0, array.length-1);
        System.out.println(Arrays.toString(array));
    }

    public static void quickSort(int[] arr, int low, int high){
        if (arr.length < 2)
            return;
        if (low > high)
            return;
        int i = low;
        int j = high;
        // temp就是基准位
        int temp = arr[low];

        while (i<j){
            //先看右边,依次往左边递减
            while (arr[j]>=temp&&i<j){  //右边应该比temp要大
                j--;
            }
            while (arr[i]<=temp&&i<j){  //左边应该比temp要小
                i++;
            }
            if (i<j){  //符合条件就置换(最终是为了实现temp左边小,右边大)
                int t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }
        }
        //最后将基准temp与 i和j相等位置的数字进行交换
        arr[low] = arr[i];
        arr[i] = temp;

        quickSort(arr, low, j-1);    //递归调用左半数组
        quickSort(arr, j+1, high);    //递归调用右半数组
    }
}

7、堆排序

        首先,堆的结构可以分为大顶堆和小顶堆,是一个完全二叉树,而堆排序事根据堆的这种数据结构设计的一种排序。其中大顶堆的性质:每个结点的值都大于其左孩子和右孩子结点的值。

 堆排序的基本思想:首先,将待排序的数组构造成一个大顶堆,此时,整个数组的最大值就是堆结构的顶端。然后,将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1。最后,将剩余的n-1个数再构造成大顶堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值