[数据结构与算法之排序算法]

排序算法

  • 排序算法介绍
    • 测试数据准备
    • 排序父类Sort的创建
    • 比较类排序算法
      • 1.选择排序
      • 2.冒泡排序
      • 3.插入排序
      • 4.希尔排序
      • 5.归并排序
        • 上述五种排序算法速度比较

排序算法介绍

我们可以将其分为两类:比较类和非比较类排序算法。
排序涉及到的相关概念:

稳定 :如果有a和两个变量值相等,排序前a在b前面,排序后a还是在b前面。
不稳定:和稳定相反,有可能a会跑到b的后面。
时间复杂度:对于排序数据的总操作次数,反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执行时所需要存储空间的容量,它也是数据规模n的函数。

排序算法分类 定义 排序算法类型
比较类排序 通过比较决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),所以也叫非线性时间比较类排序 选择排序         冒泡排序         插入排序     希尔排序             归并排序    堆排序     快速排序
非比较类排序 不通过比较元素间的相对次序,它是可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 计数排序 桶排序 基数排序

测试数据准备

package sort;

import java.util.Random;

public class ArrayData {
    //数据:完全随机,大致有序,大致平稳
    private int type;
    private int[] arr = new int[10000];
    private Random random = new Random();
    public ArrayData(int type){
        this.type = type;
    }
    public int[] makeData() {
        if (type == 0) {
            for (int i = 0; i < arr.length; i++) {
                arr[i] = random.nextInt(10000);
            }
        } else if (type == 1) {
            for (int i = 0; i < arr.length; i++) {
                arr[i] = (i + 1) * 100 + random.nextInt(300);
            }
        } else {
            for (int i = 0; i < arr.length; i++) {
                arr[i] = 5000 + i % 2 == 0 ? random.nextInt(500) : -random.nextInt(500);
            }
        }
        return arr;
    }
}

排序父类Sort的创建

package sort;

public abstract class Sort {
    public int[] arr;
    public Sort(){};
    public Sort(int[] arr){
        this.arr = new int[arr.length];
        for(int i=0;i<arr.length;i++){
            this.arr[i] = arr[i];
        }
    }
    public abstract void sort();
}

比较类排序算法

1.选择排序

选择排序是一种简单直观的排序算法,它的工作原理是首先在没有排序的序列中找到最大(小)元素,存放到排序序列的起始位置;然后再从剩余未排序的元素中继续寻找最大(小)元素,放到序列的已经排序序列的末尾,直至所有元素均排序完成。
其时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
我们是使用双层循环遍历,外层为i,内层为j,判断从i+1到最后一个元素下标,只要这个范围内有数字比下表i的值小(从小到大排序),则进行交换;

package sort;

import java.util.Arrays;

public class SelectionSort extends Sort{
    //数据分布,完全随机,大致有序,大致平稳
    //算法的执行时间除了与算法的策略有关之外,还与数据分布有关系;
    public SelectionSort(int[] arr){
        super(arr);
    }
    @Override
    public void sort() {
        for(int i = 0;i<arr.length-1;i++){
            for(int j = i+1;j<arr.length;j++){
                if(arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

[数据结构与算法之排序算法]_第1张图片

2.冒泡排序

冒泡排序是一种间的排序算法,他重复的走访要排序的数列,一次比较两个元素,如果它们的顺序错误就交换一下,走访数列的工作是重复的,直到没有需要交换的,也就是该数列已经排序完毕。
其时间复杂度为:O(n^2)
空间复杂度为:O(1)
稳定性:稳定

动态图:
[数据结构与算法之排序算法]_第2张图片

package sort;

import java.util.Arrays;

public class BubbleSort extends Sort{
    public BubbleSort(int[] arr){
        super(arr);
    }
    @Override
    public void sort() {
        for(int i=0;i<arr.length-1;i++){
            for(int j=0;j<arr.length-i-1;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));
    }
}

[数据结构与算法之排序算法]_第3张图片

3.插入排序

它的工作原理是通过构建有序序列,对于未排序序列,再已经有序的序列中从后往前扫描,找到相应的插入位置并插入。
它的时间复杂度为;O(n^2)
空间复杂度为:O(1)
稳定性:稳定

动态图演示:
[数据结构与算法之排序算法]_第4张图片
代码实现:

package sort;

import java.util.Arrays;

public class InsertionSort extends Sort{
    public InsertionSort(int[] arr){
        super(arr);
    }
    @Override
    public void sort() {
        for(int i=1;i<arr.length;i++){
            int j;
            int e = arr[i];
            for(j=i;j>0&&arr[j-1]>e;j--){
                arr[j] = arr[j-1];
            }
            arr[j] = e;
        }
        System.out.println(Arrays.toString(arr));
    }
}

[数据结构与算法之排序算法]_第5张图片

4.希尔排序

也叫缩小增量排序,它是第一个突破O(n^2)的排序算法;
它是插入排序的升级版,相比插入排序它的步长为1,所以我们定义一个变量向前减减即可,但是希尔排序的步长不定,核心还是插入排序;
其时间复杂度为:O(n^1.3)
空间复杂度为:O(1)
稳定性:不稳定

动态图演示:
[数据结构与算法之排序算法]_第6张图片
代码实现:

package sort;

import java.util.Arrays;

public class ShellSort extends Sort{
    public ShellSort(int[] arr){
        super(arr);
    }
    @Override
    public void sort() {
        int len = arr.length;
        for(int gap = len / 2;gap>0;gap=gap/2){
            for(int i = gap;i<len;i++){
                int e= arr[i];
                int j = i;
                while(j-gap >= 0 && arr[j-gap] > e) {
                    arr[j] = arr[j - gap];
                    j = j-gap;
                }
                arr[j] = e;
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

在这里插入图片描述

5.归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列;也就是先让每个子序列有序,再让子序列段间有序。若将两个有序表合并为一个有序表,成为二路归并。
其时间复杂度为:O(nlogn)
空间复杂度为:O(n)
稳定性:稳定

动态图:

代码实现:

package sort;

import java.util.Arrays;

public class MergeSort extends  Sort {
    public MergeSort(int[] arr){
        super(arr);
    }
    @Override
    public void sort() {
        mergeSort(0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    private void mergeSort(int L, int R) {
    //当做指针大于等于右指针则递归结束;
        if(L >= R){
            return;
        }
        int mid = (L+R) / 2;
        mergeSort(L,mid);//先左后右;
        mergeSort(mid+1,R)
        //如是前面的最后一个比后面的第一个元素大才向上递归。
        if(arr[mid] > arr[mid+1]){
            merge(L,mid,R);
        }
    }
	//向上合并数列
    private void merge(int L,int mid, int R) {
    	//先将原数组复制一份;
        int[] aux = new int[R-L+1];
        for(int k=L;k<=R;k++){
            aux[k-L] = arr[k];
        }
        int i = L;
        int j = mid+1;
        //判断如是前面部分已经排完,则后面部分直接赋值即可,反之一样;
        //若是都没完,则判断两部分那个元素值小先赋值。
        for(int k=L;k<=R;k++){
            if(i>mid){
                arr[k] = aux[j-L];
                j++;
            }else if(j > R){
                arr[k] = aux[i-L];
                i++;
            }else if(aux[i-L] < aux[j-L]){
                arr[k] = aux[i-L];
                i++;
            }else{
                arr[k] = aux[j-L];
                j++;
            }
        }
    }
}

[数据结构与算法之排序算法]_第7张图片

上述五种排序算法速度比较

package sort;

public class TestSort {
    public static void main(String[] args) {
        //0 完全随机 1 大致有序  2 大致平稳 数据量为10000个
        ArrayData data = new ArrayData(0);
        //ArrayData data = new ArrayData(1);
        //ArrayData data = new ArrayData(2);
        int[] arr = data.makeData();
        test01(arr);
        test02(arr);
        test03(arr);
        test04(arr);
        test05(arr);
    }
    private static void test01(int[] arr){
        BubbleSort bubbleSort = new BubbleSort(arr);
        Long start = System.currentTimeMillis();
        bubbleSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("冒泡排序所用时间:"+ (end - start));
    }
    private static void test02(int[] arr){
        SelectionSort selectionSort = new SelectionSort(arr);
        Long start = System.currentTimeMillis();
        selectionSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("选择排序所用时间:"+ (end - start));
    }
    private static void test03(int[] arr){
        InsertionSort insertionSort = new InsertionSort(arr);
        Long start = System.currentTimeMillis();
        insertionSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("插入排序所用时间:"+ (end - start));
    }
    private static void test04(int[] arr){
        ShellSort shellSort = new ShellSort(arr);
        Long start = System.currentTimeMillis();
        shellSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("哈希排序所用时间:"+(end - start));
    }

    private static void test05(int[] arr){
        MergeSort mergeSort = new MergeSort(arr);
        Long start = System.currentTimeMillis();
        mergeSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("归并排序所用时间:"+ (end - start));
    }
}

[数据结构与算法之排序算法]_第8张图片
[数据结构与算法之排序算法]_第9张图片
[数据结构与算法之排序算法]_第10张图片

你可能感兴趣的:(Java,笔记,排序算法,算法,数据结构)