算法07:常用算法排序

常用排序算法

一、十种排序算法比较

​ 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。以下为复杂度对比:

在这里插入图片描述

​ 关于稳定性的解释:稳定性为排序后 2 个相等键值的顺序和排序之前它们的顺序相同

二、排序算法的选择

​ 从上图可以明显的看出各种算法的优劣,在时间复杂度和空间复杂度两者之间很难有兼顾,所以只能根据需要选择。因此,不必记下所有算法,下面我用Java写了其中的四种常用的算法。

三、常用算法代码

0. 输入输出函数的封装

​ 将一行数字读入,并按照空格分开,形成数组的方法抽象,方便其他所有排序算法的调用。同时,输出方法也抽象于此,以备实例化调用。

import java.util.Scanner;

/**
 * @description: 提供输入和输出方法
 * @author: 宇智波Akali
 * @time: 2020/4/6 15:39
 * @fromProject: 10_sort_Methods
 * @Version: V1.0
 */
public class In_and_Out {
    public int[] setList(){
        /**
         * @Description: 将序列格式化为数组
         * @auther: 宇智波Akali
         * @date: 15:43 2020/4/6
         * @param: []
         * @return: int[]
         */
        System.out.println("请输出数组:");
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();  //读入一行字符串
        String[] str_line = input.split(" ");//将字符串按空格分隔成字符串数组
        int[] list = new int[str_line.length];
        for (int i=0;i<list.length;i++){
            list[i] = Integer.parseInt(str_line[i]);
        }
        return list;
    }
    public void printList(int[] list){
        /**
         * @Description: 传入排好序的数组,执行打印
         * @auther: 宇智波Akali
         * @date: 15:52 2020/4/6
         * @param: [list]
         * @return: void
         */
        for (Integer x: list){
            System.out.print(x + " ");
        }
    }
}

1. 冒泡排序

算法步骤

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。

  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

  • 针对所有的元素重复以上的步骤,除了最后一个。

  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码

public class Bubble_Sort_01 {
    public static void main(String[] args) {
        int [] list = new In_and_Out().setList();   //创建匿名对象调用In_and_Out中的setList方法
        new In_and_Out().printList(bubble_Sort(list));//创建匿名对象调用其中的printLis方法
    }
    //****************************算法部分*********************************
    public static int[] bubble_Sort(int[] list){
        boolean trigger = true; //使用trigger判断原始序列是否已经有序
        for (int i=list.length-1 ;i>=0;i--){
            for (int j=0;j<i;j++){
                if (list[j] > list[j+1]){   //将大于号改为小于则变成从大到小排序
                    int temp;
                    temp = list[j+1];
                    list[j+1] = list[j];
                    list[j] = temp;
                    trigger = false;
                }
            }
            if (trigger) break;
        }
        return list;
    }

}

2. 插入排序

算法步骤

  • 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

  • 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

代码

public class Bubble_Sort_01 {
    public static void main(String[] args) {
        int [] list = new In_and_Out().setList();   //创建匿名对象调用In_and_Out中的setList方法
        new In_and_Out().printList(bubble_Sort(list));//创建匿名对象调用其中的printLis方法
    }
    //****************************算法部分*********************************
    public static int[] bubble_Sort(int[] list){
        boolean trigger = true; //使用trigger判断原始序列是否已经有序
        for (int i=list.length-1 ;i>=0;i--){
            for (int j=0;j<i;j++){
                if (list[j] > list[j+1]){   //将大于号改为小于则变成从大到小排序
                    int temp;
                    temp = list[j+1];
                    list[j+1] = list[j];
                    list[j] = temp;
                    trigger = false;
                }
            }
            if (trigger) break;
        }
        return list;
    }

}

3. 归并排序

算法步骤

  • 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

  • 设定两个指针,最初位置分别为两个已经排序序列的起始位置;

  • 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

  • 重复步骤 3 直到某一指针达到序列尾;

  • 将另一序列剩下的所有元素直接复制到合并序列尾。

代码

import java.util.Arrays;

public class Merge_Sort_03 {
    public static void main(String[] args) {
        int[] list = new In_and_Out().setList();//读入并格式化List
        new In_and_Out().printList(merge_sort(list));//打印
    }
    //********************算法部分*********************************
    public static int[] merge_sort(int[] list){
        if (list.length < 2){           //递归边界:数组长度小于2,将数组递归划分为单个元素
            return  list;
        }
        int middle = list.length/2;//定义中间下标
        int[] L_list = Arrays.copyOfRange(list,0,middle);   //定义左数组及内容范围
        int[] R_list = Arrays.copyOfRange(list, middle,list.length);//定义右数组及内容范围
        return merge(merge_sort(L_list), merge_sort(R_list));       //递归调用,进行归并排序
    }
    protected static int[] merge(int[] L, int[] R){
        int[] result = new int[L.length+R.length];
        int i = 0;
        while (L.length>0 && R.length>0){
            if (L[0] <= R[0]){                 //小于改为大于则变成从大到小排序
                result[i++] = L[0];           //左列的第一项小于右列第一项则向结果数组中填入L[0]
                L = Arrays.copyOfRange(L,1,L.length);//将L的左边第一个去掉,之前的第二个变成第一个
            }else {
                result[i++] = R[0];
                R = Arrays.copyOfRange(R,1,R.length);
            }
            //每次左or右列长度减小1,直到两个的长度其中有一个为0,即有一边数组全部加到result中
            //这时候还剩一个数组,剩余部分必然都大于之前的数组,直接加入即可
        }
        while (L.length > 0) {
            result[i++] = L[0];
            L = Arrays.copyOfRange(L, 1, L.length);
        }
        while (R.length > 0) {
            result[i++] = R[0];
            R = Arrays.copyOfRange(R, 1, R.length);
        }
        return result;
    }
}

4. 快速排序

算法步骤

  • 从数列中挑出一个元素,称为 “基准”(pivot);

  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

代码

public class Quick_Sort_04 {
    public static void main(String[] args) {
        int[] list = new In_and_Out().setList();        //输入
        new In_and_Out().printList(quick_sort(list));   //输出
    }
    //*************************算法部分**************************
    private static int[] quick_sort(int[] list){
        return sort(list, 0, list.length-1);
    }
    private static int[] sort(int[] list, int L, int R){
        if (L < R){
            int partitionIndex = partition(list, L, R);         //接收一个已经确定了位置的数的下标,以此为分界线分块递归
            sort(list, L, partitionIndex - 1);
            sort(list, partitionIndex + 1, R);
        }
        return list;
    }
    private static int partition(int[] list, int L, int R){
        int pivot_key = list[L];
        while (L < R){
            //一次外层循环只解决一次交换
            while (L < R && list[R] >= pivot_key){
                R--;
            }
            //将小于基准的放左边
            list[L] = list[R];
            while (L < R && list[L] <= pivot_key){
                L++;
            }
            //将大于基准的放右边
            list[R] = list[L];
        }
        list[L] = pivot_key;    //当循环结束时,L=R,两者重合,将pivot_key的值放在此处,就确定了一个数的位置
        //返回基准最后的位置
        return L;
    }
}

发布了27 篇原创文章 · 获赞 19 · 访问量 4531

猜你喜欢

转载自blog.csdn.net/qq_43617268/article/details/105351537