数据结构-高级排序

最近事情比较多,没有好好看书。今天的的学习内容是高级排序。
高级排序主要介绍的就是希尔排序,快速排序,基数排序。
1-希尔排序
基本原理就是通过增加比较数据之间的步长,是数据快速移动到其排序后位置的附近,从而避免了像插入排序一样一步一步的移动到自己的位置上。希尔排序在一次排序中也是使用的插入排序。
希尔排序的设计关键就是确定步长。Knuth序列采用公式 h=3*h + 1。首先根据从h=1开始计算h的指,直到h大于数据个数。
然后在排序过程中在逆序计算h作为步长,执行插入排序,最后h=1,相当于执行了一个插入排序。但是此时数据已经基本有序了。
排序代码实现:

public class ShellSort {

    private long[] ar;
    private int nElems;

    public ShellSort(int max) {
        ar = new long[max];
        nElems = 0;
    }

    public void insert(long value) {
        if (nElems == ar.length) {
            return;
        }
        ar[nElems] = value;
        nElems++;
    }

    public void sort() {
        int inner, outer;
        long temp;

        int h = 1;
        // 在这里为什么使用的比较条件不是h<nElems呢?
        // 因为条件满足的条件下应该是会再*3的,随意应该使用/3比较,保证下次判断的时候是正确的计算结果。
        while (h <= nElems / 3) {
            h = h * 3 + 1;
        }

        while (h > 0) {
            for (outer = 0; outer < nElems; outer++) {
                temp = ar[outer];
                inner = outer;
                while (inner > h - 1 && ar[inner - h] >= temp) {
                    ar[inner] = ar[inner - h];
                    inner = h;
                }
                ar[inner] = temp;

            }
            h = (h - 1) / 3;
        }
    }

}

希尔排序的步长计算公式不是固定的。算法设计之初采用二分方法计算步长,但是效率并不少。然后就是用3倍的计算方法。还有5倍的计算方法等。
目前为止还没有确定结论说明希尔排序的效率。但是一般应该就是O(N*(logN)²)。

2-快速排序
快速排序采用的就是划分和递归的算法处理。
实现代码如下:

public void quickSort(int left, int right) {
        if (left >= right) {
            return;
        }
        long pivot = ar[right];

        int part = partint(left, right, pivot);// 执行一次划分
        quickSort(left, part - 1);// 递归的方法,实现了子部分的快速排序
        quickSort(part + 1, right);

    }

    public int partint(int left, int right, long pivot) {
        int leftPtr = left - 1;
        int rightPtr = right;
        while (true) {
            while (ar[++leftPtr] < pivot)// 查找左侧的大值
                ;

            while (rightPtr > 0 && ar[--rightPtr] > pivot)// 查找右侧的小值
                ;

            if (leftPtr >= rightPtr) {// 一趟划分执行结束
                break;
            } else {
                swap(left, right);
            }

        }
        swap(leftPtr, right);
        return -1;
    }

    private void swap(int left, int right) {
        long temp = ar[left];
        ar[left] = ar[right];
        ar[right] = temp;
    }

快速排序的效率达到了O(N*LogN)。
以上的快速排序的枢纽选择为数据最右侧数据。在数列的顺序基本无序的情况下相对平均,性能还好。如果是对逆序排序,那么机会发生不停的交换,导致快速的性能下降到了O(N²)。
关键就在于枢纽的选择一只都是序列最右侧数据。可以通过改变枢纽的选择规则来弥补这种情况。
可以使用数据最左侧、中间、最右侧三个数之间的中间值作为枢纽,而且选择枢纽的过程中,这三个数就已经排好序了。
同时快速在大数据集中的排序性能优势非常明显,但是对于小数据集基本没什么优势。有时候可能还要更慢一些。
因此可以对快速排序的方法进行一个判定,如果数据集小于100,就采用插入排序。如果大于100,再使用快速排序,同时采用三数据项取中间的方法来获得枢纽值。本快速排序方法采用递归的方法,也可以通过引入栈结构消除递归。
3-基数排序
还有一种比较有意思的排序方法就是基数排序。这种方法的原理与之前的不同,是通过数字的分解,通过对应位数的比较来进行排序。
基数排序貌似非常高效,但实际上和快速排序差不多,而且需要的空间是快速排序的两倍。

本次学习的内容主要是高级排序中的基数排序和快速排序,下一次准备学习二叉树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值