排序算法的实现

排序算法

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

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

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

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

相关概念

  • 稳定:如果a原本在b前面,而a==b,排序之后a仍然在b的前面。
  • 不稳定:如果a原本在b的前面,而a==b,排序之后 a 可能会出现在 b 的后面。
  • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
  • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

排序接口

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;
    }
}

选择排序

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕

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);
                }
            }
        }
    }
}

冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成

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

插入排序

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入

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

希尔排序

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;
            }
        }
    }
}

归并排序

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2路归并

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++;
            }
        }
    }
}

快速排序

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

单路快速排序

public class QuickSort extends Sort{
    public QuickSort(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 j = L;
        for(int i = L + 1; i <= R; i++){
            if(arr[i] > v){
                swap(j + 1 , i);
                j++;
            }
        }
        swap(L, j);
        return j;
    }
}

双路快速排序

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

    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(arr[i] < v && i <= R){
                i++;
            }
            while(j >= L + 1 && arr[j] > v){
                j--;
            }
            if(i > j){
                break;
            }
            swap(i, j);
            i++;
            j--;
        }
        swap(L, j);
        return j;
    }
}

三路快速排序

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

    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);
    }
}

计数排序

public class CountingSort extends Sort{
    public CountingSort(int arr[]){
        super(arr);
    }

    @Override
    public void sort() {
        int max = arr[0];
        int min = arr[0];
        for(int i = 0; i < arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
            }
            if(arr[i] < min){
                min = arr[i];
            }
        }

        int counts[] = new int [max - min + 1];

        for(int i = 0; i < arr.length; i++){
            counts[arr[i] - min]++;
        }
        int k = 0;
        for(int index = 0; index < counts.length; index++){
            for(int count = 0; count < counts[index]; count++){
                int num = index + min;
                arr[k++] = num;
            }
        }
    }
}

桶排序

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

public class BucketSort extends Sort{
    public BucketSort(int arr[]){
        super(arr);
    }
    @Override
    public void sort() {
        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];
            }
        }
        int buckeNum = (max - min) / arr.length + 1;
        ArrayList<Integer> list[] = new ArrayList[buckeNum];
        for(int i = 0; i <list.length; i++){
            list[i] = new ArrayList<>();
        }

        for(int i = 0; i < arr.length; i++){
            list[(arr[i] - min) / arr.length].add(arr[i]);
        }

        for(int i = 0; i < list.length; i++){
            list[i].sort(new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1 - o2;
                }
            });
        }
        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);
            }
        }
    }
}

基数排序

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

public class RadixSort extends Sort{
    public RadixSort(int arr[]){
        super(arr);
    }
    @Override
    public void sort() {
        int radix = getRadix();
        LinkedList<Integer>[] list = new LinkedList[10];
        for(int i = 0; i < list.length; i++){
            list[i] = new LinkedList<>();
        }
        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;
            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();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值