数据结构与算法入门——排序算法之八大常用排序方法

冒泡排序

   //定义一个数组
        int[] arr = new int[]{8,5,7,6,1,3,9,4};
        //共比较多少轮
        for (int i = 0; i < arr.length-1; i++) {
            //一轮比较多少次
            for (int j = 0; j < arr.length-1-i; j++) {
                //如果前面的大于后面的,那么前后交换
                if (arr[j]>arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));

快速排序

 /**
     *
     * @param arr:传入的参数数组
     * @param start:排序区间开始的下标
     * @param end:排序区间结束的下标
     */
    public static void quickSort(int[] arr,int start,int end){
        //如果开始下标没有与结束下标重合,则一直循环
        if (start < end){
            //将当前排序区间的第一个数作为比较的标准数
            int  stard = arr[start];
            //记录排序需要的下标
            int low = start;
            int high = end;
            //如果开始坐标小于结束坐标,则开始循环
            while (low<high){
                //如果开始坐标小于结束坐标并且右边的数大于左边的标准数
                while (low<high&&stard<=arr[high]){
                    //结尾坐标向前挪一位
                    high--;
                }
                //右边结束坐标的数替换掉左边开始坐标的数
                arr[low] = arr[high];
                //如果开始坐标小于结束坐标并且左边的数小于标准数
                while (low<high&&arr[low]<=stard){
                    //左边数的下标向前挪一位
                    low++;
                }
                //左边开始坐标的数替换掉右边结束坐标的数
                arr[high] = arr[low];
            }
            //当循环结束,即两坐标重叠时,将比较的标准数赋给当前坐标的值
            arr[low] = stard;
            //重新开始比较标准数左边的区间
            quickSort(arr,start,low);
            //重新开始比较标准数右边的区间
            quickSort(arr,low+1,end);
        }
    }

插入排序

public static void insertSort(int[] arr){
        int temp;
        int j = 0;
        //从第二个遍历整个数组
        for (int i = 1; i < arr.length; i++) {
            //如果当前数比前一个数小
            if (arr[i]<arr[i-1]){
                //把当前数存起来
                temp = arr[i];
                //遍历当前数之前的所有的数
                for (j = i-1; j >=0&&temp<arr[j] ; j--) {
                    //如果遍历到的数大于temp,则向后挪一位
                    arr[j+1] = arr[j];
                }
                //当前的数小于等于temp,则把temp赋值给他后一位数
                arr[j+1] = temp;
            }
        }
    }

希尔排序

public static void shellSort(int[] arr){
        //遍历所有的步长
        for (int d = arr.length/2; d >0 ; d/=2) {
            //遍历每一组中的第一个元素,与同一组的元素进行比较
            for (int i = d; i < arr.length; i++) {
                //遍历本组中的所有元素
                for (int j = i-d; j >=0 ; j-=d) {
                    if (arr[j]>arr[j+d]){
                        int temp = arr[j];
                        arr[j] = arr[j+d];
                        arr[j+d] = temp;
                    }
                }
            }
        }
    }

选择排序

 public static void chooseSort(int[] arr){
        //遍历所有的数
        for (int i = 0; i <arr.length ; i++) {
            int minIndex = i;
            //把当前的数与之后所有的数全都比较一遍。并记录下最小的数的下标
            for (int j = i+1; j <arr.length ; j++) {
                if (arr[j]<arr[minIndex]){
                    minIndex = j;
                }
            }
            //将最小的数与当前遍历的数交换
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
        }
    }

归并排序

 public static void MergeSort(int[] arr,int start,int end){
        //取出中间下标
        int middel = (start+end)/2;
        //只要开始下标小于结束下标,就会一直递归
        if (start<end){
            //处理左边的数组
            MergeSort(arr,0,middel);
            //处理右边的数组
            MergeSort(arr,middel+1,end);
            //归并排序
            merge(arr,0,middel,end);
        }
    }

    public static void merge(int[] arr,int low,int middel,int high){
        //用于储存归并后的临时数组
        int[] temp = new int[high-low+1];
        //记录第一个数组中需要遍历的下标
        int i = low;
        //记录第二个数组中需要遍历的下标
        int j = middel+1;
        //用于记录在临时数组中存放的下标
        int index = 0;
        //遍历两个数组中取出较小的数字,存放到新数组中
        while (i<=middel&&j<=high){
            //第一个数组的数字更小
            if (arr[i]<=arr[j]){
                temp[index] = arr[i];
                //下标后移一位
                i++;
                //第二个数组的数字更小
            }else {
                temp[index] = arr[j];
                j++;
            }
            index++;
        }
        //处理多余的数据
        while (j<=high){
            temp[index]=arr[j];
            j++;
            index++;
        }
        while (i<=middel){
            temp[index]=arr[i];
            i++;
            index++;
        }
        //把临时数组中的数据重新存入原数组
        for (int k = 0; k < temp.length; k++) {
            arr[k+low] = temp[k];
        }
    }

基数排序

/**
 * 采用数组形式
 */
  public static void radixSort(int[] arr){
        //定义一个最小值变量。Integer.MIN_VALUE:整形数中的最小值:-2147483648
        int max = Integer.MIN_VALUE;
        //遍历找出数组中最大值
        for (int i = 0; i < arr.length; i++) {
            if (arr[i]>max){
                max = arr[i];
            }
        }
        //计算最大数组是几位数
        int maxLength = (max+"").length();
        //定义一个临时存储数据的二维数组
        int[][] temp = new int[10][arr.length];
        //用于记录temp相对数组中数据的数量
        int[] count = new int[10];
        //根据最大长度决定比较次数,即最大数是几位数,则比较几次
        for (int i = 0,n=1; i < maxLength; i++,n*=10) {
            //把每一个数字分别计算余数,按余数分组
            for (int j = 0; j < arr.length; j++) {
                //计算余数
                int ys = arr[j]/n%10;
                //把当前遍历的数据放入指定的数组中
                temp[ys][count[ys]] = arr[j];
                //当前数组数据数量+1
                count[ys]++;
            }
            //记录取的元素需要放的位置
            int index = 0;
            //再把分完组的数据重新放回原数组中
            for (int k = 0; k <count.length ; k++) {
                //判断当前分组是否为0
                if (count[k]!=0)
                    //若不为0,则遍历取出当前分组的数据
                    for (int l = 0; l < count[k]; l++) {
                        //原数组从0开始,临时数组从有数据的分组开始
                        arr[index] = temp[k][l];
                        //原数组下标+1
                        index++;
                    }
                //取完后把count数组清空以便记录下一次便利分组
                count[k] = 0;
            }
        }

    }

/**
 * 采用队列形式
 */
  public static void radixSort_for_queue(int[] arr){
        //定义一个最小值变量。Integer.MIN_VALUE:整形数中的最小值:-2147483648
        int max = Integer.MIN_VALUE;
        //遍历找出数组中最大值
        for (int i = 0; i < arr.length; i++) {
            if (arr[i]>max){
                max = arr[i];
            }
        }
        //计算最大数组是几位数
        int maxLength = (max+"").length();
        //定义一个临时存储数据的队列的数组(即创建10个队列)
        QueueUtil[] temp = new QueueUtil[10];
        //为每一组队列赋值
        for (int i = 0; i < temp.length; i++) {
            temp[i] = new QueueUtil();
        }
        //根据最大长度决定比较次数,即最大数是几位数,则比较几次
        for (int i = 0,n=1; i < maxLength; i++,n*=10) {
            //把每一个数字分别计算余数,按余数分组
            for (int j = 0; j < arr.length; j++) {
                //计算余数
                int ys = arr[j]/n%10;
                //把当前遍历的数据放入指定的队列中
                temp[ys].add(arr[j]);
            }
            //记录取的元素需要放的位置
            int index = 0;
            //再把分完组的数据重新放回原数组中
            for (int k = 0; k <temp.length ; k++) {
                //判断当前分组是否为0
                while (!temp[k].isEmpty()){
                    //原数组从0开始,队列从有数据的开始
                    arr[index] = temp[k].pop();
                    //原数组下标+1
                    index++;
                }
            }
        }
    }

堆排序

  • 堆排序涉及到二叉树的知识,如果没接触过二叉树的道友可先看这篇文章
     https://blog.csdn.net/qq_40181435/article/details/104733767
    
/**
 * 升序用大顶堆
 * 降序用小顶堆
 * */
 
  public static void heapSort(int[] arr){
        int start = (arr.length-1)/2;
        //调整为大顶堆
        for (int i = start; i >=0; i--) {
            maxHeap(arr,arr.length,i);
        }
        //先把数组中前后交换,然后再把前面的处理成大顶堆
        for (int i = arr.length-1; i >0 ; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            maxHeap(arr,i,0);
        }

    }

    /**
     * @param arr:传递的数组
     * @param size:排序的范围
     * @param index:初始父节点
     */
    public static void maxHeap(int[] arr,int size,int index){
        //左子结点
        int leftNode = 2*index+1;
        //右子结点
        int rightNode = 2*index+2;
        //父节点
        int max = index;
        //与两个子结点对比,找出最大节点
        if (leftNode<size&&arr[leftNode]>arr[max]){
            //如果左子结点大于父节点,那么二者交换
            max = leftNode;
        }
        if (rightNode<size&&arr[rightNode]>arr[max]){
            //如果右子结点大于父节点,那么二者交换
            max = rightNode;
        }
        //交换位置
        if (max != index){
            int temp = arr[index];
            arr[index] = arr[max];
            arr[max] = temp;
            maxHeap(arr,size,max);
        }
        //交换位置后,可能破坏之前排好的堆,所以需要重新调整之前排好的堆

    }
 
发布了23 篇原创文章 · 获赞 5 · 访问量 1145

猜你喜欢

转载自blog.csdn.net/qq_40181435/article/details/104717122