数据结构之排序算法

一.排序算法

就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

1.比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。

选择排序、冒泡排序、插入排序、希尔排序、归并排序、堆排序、快速排序

2.非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

计数排序、桶排序、基数排序

3.稳定:如果a原本在b前面,而a==b,排序之后a仍然在b的前面。

4.不稳定:如果a原本在b的前面,而a==b,排序之后 a 可能会出现在 b 的后面。

5.时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。

6.空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

二.十大排序

1.选择排序

       选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

时间复杂度:O(n^2) 空间复杂度: O(1)   稳定性: 不稳定

2.冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

时间复杂度:O(n^2)   空间复杂度:O(1)   稳定性: 稳定

3.插入排序

       插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

时间复杂度:O(n^2)   空间复杂度:O(1)   稳定性: 稳定

4.希尔排序

       1959年Shell发明,第一个突破O(n^2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

时间复杂度:O(n^1.3)   空间复杂度:O(1)   稳定性: 不稳定

5.归并排序

         归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2路归并。

时间复杂度:O(nlogn)   空间复杂度:S(n)   稳定性: 稳定

6.堆排序

       堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

时间复杂度:O(nlog2n)   空间复杂度:O(1)   稳定性: 不稳定

7.快速排序

       快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,比另一部分的关键字大,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

时间复杂度:O(nlogn)   空间复杂度:O(1)   稳定性:不稳定

8.计数排序

       计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

时间复杂度:O(n+m)   空间复杂度:O(n+m)   稳定性:稳定

9.桶排序

       桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

时间复杂度:O(n+m)   空间复杂度:O(n+m)   稳定性:稳定

10.基数排序

        基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

时间复杂度:O(n+m)   空间复杂度:O(n+m)   稳定性:稳定

三.代码

1.Test

package p5.排序算法;

/*
算法的执行时间
除了跟算法的策略有关系之外
还跟数据分布情况有关系
数据分布情况:
        完全随机    大致有序    大致平稳
选择      5           5          4
冒泡      4           4          5
插入      3           1          3
希尔      2           3          2
归并      1           2          1
单快      1+          3+         1+
双快      1+          1+         1+
三快      n           n          n
基排      3-          4          3-
桶排序    4+          3-         4+
*/
public class TestSort {
    public static void main(String[] args) {
        ArrayData data = new ArrayData(0);
        int[] arr = data.makeData();
        test01(arr);
        test02(arr);
        test03(arr);
        test04(arr);
        test05(arr);
        test06(arr);
        test07(arr);
        test08(arr);
        test09(arr);
        test10(arr);
    }
    private static void test10(int[] arr) {
        BucketSort bucketSort = new BucketSort(arr);
        Long start = System.currentTimeMillis();
        bucketSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("桶排序:" + (end - start) + "ms");
    }

    private static void test09(int[] arr) {
        RadixSort radixSort = new RadixSort(arr);
        Long start = System.currentTimeMillis();
        radixSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("基数排序:" + (end - start) + "ms");
    }

    private static void test08(int[] arr) {
        QuickSort03 quickSort03 = new QuickSort03(arr);
        Long start = System.currentTimeMillis();
        quickSort03.sort();
        Long end = System.currentTimeMillis();
        System.out.println("三路快排:" + (end - start) + "ms");
    }

    private static void test07(int[] arr) {
        QuickSort02 quickSort02 = new QuickSort02(arr);
        Long start = System.currentTimeMillis();
        quickSort02.sort();
        Long end = System.currentTimeMillis();
        System.out.println("双路快排:" + (end - start) + "ms");
    }

    private static void test06(int[] arr) {
        QuickSort01 quickSort01 = new QuickSort01(arr);
        Long start = System.currentTimeMillis();
        quickSort01.sort();
        Long end = System.currentTimeMillis();
        System.out.println("单路快排:" + (end - start) + "ms");
    }

    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) + "ms");
    }

    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) + "ms");
    }

    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) + "ms");
    }

    private static void test02(int[] arr) {
        BubbleSort bubbleSort = new BubbleSort(arr);
        Long start = System.currentTimeMillis();
        bubbleSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("冒泡排序: " + (end - start) + "ms");
    }

    private static void test01(int[] arr) {
        SelectionSort selectionSort = new SelectionSort(arr);
        Long start = System.currentTimeMillis();
        selectionSort.sort();
        Long end = System.currentTimeMillis();
        System.out.println("选择排序: " + (end - start) + "ms");
    }
}

2.ArrayData

package p5.排序算法;

import java.util.Random;

public class ArrayData {
    //产生数据 完全随机0 大致有序1 大致平稳2
    private int type;
    private Random random = new Random();
    private int[] arr = new int[10000];
    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;
    }
}

3.Sort

package p5.排序算法;

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();
    public void swap(int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

4.选择排序

package p5.排序算法;

//选择排序 O(n^2) S(1) 不稳定
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]) {
                    swap(i,j);
                }
            }
        }
    }
}

5.冒泡排序

package p5.排序算法;

//冒泡排序 O(n^2) S(1) 稳定
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]) {
                    swap(j,j + 1);
                }
            }
        }
    }
}

6.插入排序

package p5.排序算法;

//插入排序 O(n^2) S(1) 稳定
public class InsertionSort extends Sort{
    public InsertionSort(int[] arr) {
        super(arr);
    }
    @Override
    public void sort() {
        for (int i = 0; i < arr.length; i++) {
            int e = arr[i];
            int j = 0;
            for (j = i; j > 0 && arr[j - 1] > e; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = e;
        }
    }
}

7.希尔排序

package p5.排序算法;

//希尔排序 O(n^1.3) S(1) 不稳定
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;
            }
        }
    }
}

8.归并排序

package p5.排序算法;

//归并排序 O(nlogn) S(n) 稳定
public class MergeSort extends Sort{
    public MergeSort(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        mergeSort(0, arr.length - 1);
    }

    private void mergeSort(int L, int R) {
        if (L >= R) {
            return;
        }
        int mid = (L + R) / 2;
        //递归排序当前层级的左边
        mergeSort(L, mid);
        //递归排序当前层级的右边
        mergeSort(mid + 1, R);

        //左边排序完了 右边排序也完了
        //将左右进行合并
        //特殊 如果左边的最大值arr[mid]小于等于右边的最小值arr[mid+1] 则不需要合并
        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];
        //复制当前层级中  原数组的内容给aux
        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++;
            }
        }
    }
}

9.单路快速排序

package p5.排序算法;

import java.security.PublicKey;

//单路快速排序
public class QuickSort01 extends Sort{
    public QuickSort01(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        quickSort(0, arr.length - 1);
    }

    private void quickSort(int L, int R) {
        if (L >= R) {
            return;
        }
        //先对数组进行划分 并返回划分后的中点
        int p = partition(L, R);
        quickSort(L, p - 1);
        quickSort(p + 1, R);
    }

    private int partition(int L, int R) {
        //优化一下 随机让后面的数字和第一个数字换一下
        //尽量避免极端情况
        swap(L, (int) (Math.random() * (R - L + 1) + L));
        int v = arr[L];
        //arr[l+1 ~ j] < v < arr[j+1 ~ i)
        int j = L;
        for (int i = L + 1; i <= R; i++) {
            if (arr[i] < v) {
                swap(j + 1, i);
                j++;
            }
        }
        swap(L, j);
        return j;
    }
}

10.双路快速排序

package p5.排序算法;

//双路快速排序
public class QuickSort02 extends Sort{
    public QuickSort02(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        quickSort(0, arr.length - 1);
    }

    private void quickSort(int L, int R) {
        if (L >= R) {
            return;
        }
        //对数组进行划分 并返回划分后的中点
        int p = partition(L, R);
        quickSort(L,p - 1);
        quickSort(p + 1, R);
    }

    private int partition(int L, int R) {
        //优化一下 随机让后面的数字和第一个数字换一下
        //尽量避免极端情况(升序情况)
        swap(L, (int) (Math.random() * (R - L + 1) + L));
        int v = arr[L];
        int i = L + 1;
        int j = R;
        while (true) {
            while (i <= R && arr[i] < v) {
                i++;
            }
            while (j >= L + 1 && arr[j] > v) {
                j--;
            }
            if (i > j) {
                break;
            }
            swap(i, j);
            i++;
            j--;
        }
        swap(L, j);
        return j;
    }
}

11.三路快速排序

package p5.排序算法;

//三路快速排序
public class QuickSort03 extends Sort {
    public QuickSort03(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        quickSort(0, arr.length - 1);
    }

    private void quickSort(int L, int R) {
        if (L >= R) {
            return;
        }
        swap(L, (int) (Math.random() * (R - L + 1) + L));
        int v = arr[L];
        int lt = L;
        int gt = R + 1;
        int i = L + 1;
        while (i < gt) {
            if (arr[i] < v) {
                swap(i, lt + 1);
                lt++;
                i++;
            } else if (arr[i] > v) {
                swap(i, gt - 1);
                gt--;
            } else {
                i++;
            }
        }
        swap(L, lt);
        quickSort(L,lt - 1);
        quickSort(gt, R);
    }
}

12.桶排序

package p5.排序算法;

import java.util.ArrayList;
import java.util.Comparator;

//桶排序
public class BucketSort extends Sort {
    public BucketSort(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        //1.找到最大值和最小值
        int max = arr[0];
        int min = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
            if (arr[i] < min) {
                min = arr[i];
            }
        }
        //2.确定桶的个数并创建桶
        int bucketNum = (max - min) / arr.length + 1;
        ArrayList list[] = new ArrayList[bucketNum];
        for (int i = 0; i < list.length; i++) {
            list[i] = new ArrayList<>();
        }
        //3.遍历源数据 将数据进行分类处理
        for (int i = 0; i < arr.length; i++) {
            list[(arr[i] - min) / arr.length].add(arr[i]);
        }
        //4.对每一个桶进行排序
        for (int i = 0; i < list.length; i++) {
            list[i].sort(new Comparator() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1 -o2;
                }
            });
//            System.out.println("第" + (i+1) + "个桶:" + list[i].toString());
        }
        //5.将所有桶中的数据依次返回到原数组中即可
        int index = 0; //原数组的角标
        for (int i = 0; i < list.length; i++) {
            for (int j = 0; j < list[i].size(); j++) {
                arr[index++] = list[i].get(j);
            }
        }
//        System.out.println(Arrays.toString(arr));
    }
}

13.基数排序

package p5.排序算法;

import java.util.LinkedList;

//基数排序
public class RadixSort extends Sort {
    public RadixSort(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        //1.找 分类-收集 的轮数(最大值的长度)
        int radix = getRadix();
        //2.创建桶 list所有桶的集合 每一个桶是LinkedList当成队列来用
        LinkedList[] list = new LinkedList[10];
        for (int i = 0; i < list.length; i++) {
            list[i] = new LinkedList<>();
        }
        //3.开始 分类-收集
        for (int r = 1; r <= radix; r++) {
            //分类过程
            for (int i = 0; i < arr.length; i++) {
                list[getIndex(arr[i], r)].offer(arr[i]);
            }
            int index = 0; //遍历arr原数组
            //收集的过程
            for (int i = 0; i < list.length; i++) {
                while (!list[i].isEmpty()) {
                    arr[index++] = list[i].poll();
                }
            }
        }
    }

    private int getIndex(int num, int r) {
        int ret = 0;
        for (int i = 1; i <= r; i++) {
            ret = num % 10;
            num /= 10;
        }
        return ret;
    }

    private int getRadix() {
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        return (max + "").length();
    }
}

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