java排序算法


排序算法

对一序列对象根据某个关键字进行排序


一、冒泡排序(Bubble Sort)

1.原理

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

2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数;

3.针对除了最后一个之外的所有的元素重复以上的步骤;

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

2.代码实现

public static long[] bubblesort(long[] array) {
        if(array.length==0)
            return array;
        for (int i = 0; i <array.length; i++) {
            for (int j = 0; j <array.length-1-i ; j++) {
                if (array[j]>array[j]){
                    long temp= array[j];
                    array[j]=array[j];
                    array[j]=temp;
                }
            }
        }
        return array;
    }

二、快速排序(Quick Sort)

1.原理

1.在数组中选一个基准数pivot(我选取了数字的最后一个数字作为基准数);

2.通过“遍历的方式”,比较给定元素和区间内其他元素的大小关系,形成<=pivot,pivot,>=pivot三个区间;

3.对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序。

2.代码实现

public static void quickSort(long[] array) {
        quickSortRange(array, 0, array.length - 1);
    }
    // 为了代码书写方便,我们选择使用左闭右闭的区间表示形式
    // 其中,from,to 下标的元素都算在区间的元素中
    // 左闭右闭的情况下,区间内的元素个数 = to - from + 1;
    private static void quickSortRange(long[] array, int from, int to) {
        if (to - from + 1 <= 1) {
            // 区间中元素个数 <= 1 个
            return;
        }
        // 挑选中区间最右边的元素 array[to]
        int pi = partitionMethodA(array, from, to);
        quickSortRange(array, from, pi - 1);    
        // 针对小于等于 pivot 的区间做处理
        quickSortRange(array, pi + 1, to);   
        // 针对大于等于 pivot 的区间做处理
    }

    private static int partitionMethodA(long[] array, int from, int to) {
        // 1. 先把 pivot 找出来
        long pivot = array[to];
        // 2. 通过定义 left 和 right 两个下标,将区间划分出来
        int left = from;
        int right = to;
        // [from, left)   都是 <= pivot 的
        // [left, right)  都是未参与比较的
        // [right, to]    都是 >= pivot 的
        while (left < right) {
            // 随着 left 在循环过程中一直在 left++,请问 left < right 的条件不一定能保证,所以,我们时刻进行 left < right 条件的保证
            while (left < right && array[left] <= pivot) {
                left++;
            }
            while (left < right && array[right] >= pivot) {
                right--;
            }
            // 循环停止时,说明 array[right] < pivot
            // 两边都卡住时,交换 [left] 和 [right] 位置的元素
            long t = array[left];
            array[left] = array[right];
            array[right] = t;
        }
        long t = array[to];
        array[to] = array[left];
        array[left] = t;
        // 返回 pivot 最终所在下标
        return left;
    }

三、选择排序(Selection Sort)

1.原理

1.遍历所有数据,先在数据中找出最大或最小的元素,放到序列的起始;
2.再从余下的数据中继续寻找最大或最小的元素,依次放到序列中;
3.直到所有数据有序。

2.代码实现

public static long[] selectionsort(long[] array){
        if (array.length == 0)
            return array;
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i+1; j < array.length; j++) {
                if (array[j] < array[minIndex]) 
                //找到最小的数
                    minIndex = j; 
                    //将最小数的索引保存
            }
            long temp = array[minIndex];
            array[minIndex] = array[i];
            array[i] = temp;
        }
        return array;
    }

四、插入排序(Insertion Sort)

1.原理

将前i个(初始为1)数据假定为有序序列,依次遍历数据,将当前数据插入到前述有序序列的适当位置,形成前i+1个有序序列,依次遍历完所有数据,直至序列中所有数据有序。

2.代码实现

// [from, to] 是左闭右闭的
    private static void insertSortRange(long[] array, int from, int to) {
        int size = to - from;
        for (int i = 0; i < size; i++) {
            // 有序区间 [from, from + i]
            // 无序区间 [from + i + 1, to]
            // 选中的无序区间的第一个元素 array[from + i + 1]
            long key = array[from + i + 1];
            int j;
            for (j = from + i; j >= from && array[j] > key; j--) {
                array[j + 1] = array[j];
            }
            array[j + 1] = key;
        }
    }

五、希尔排序(Shell Sort)

1.原理

先将整个数据序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全部数据进行依次直接插入排序,直至所有数据有序。

2.实现代码

public static long[] shellsort(long[] array,int gap){
        for (int i = 0; i < array.length-gap; i++) {
            //[0,i+gap)为有序区间,[i+gap,n)为无序区间
            long k=array[i+gap];
            //无序区间的第一个
            int j;
            for (j = i; j >0&&k<array[j] ; j=j-gap) {
                array[j+gap]=array[j];
            }
            array[j+gap]=k;
        }
        return array;
    }

六、堆排序(Heap Sort)

1.原理

堆排序利用堆这种近似完全二叉树的数据结构进行排序。堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。以最大堆为例,堆中的最大值总是位于根节点。首先将待排序的n个数据构造为大根堆,将顶端数据与末尾数据进行交换并将堆的尺寸减一,然后剩余n-1个数据再次构造为大根堆,再次交换,再次缩减,直至所有数据有序。

2.实现代码

public static void heapSort(long[] array) {
        // 建立大堆
        createBigHeap(array);
        for (int i = 0; i < array.length - 1; i++) {
            //交换之前的无序区间 [0, n - i)
            swap(array, 0, array.length - i - 1);
            // 交换之后的无序区间 [0, n - i - 1),元素个数 n - i - 1 个
            // 对堆的 [0] 进行向下调整,堆里的元素个数就是无序区间的元素个数
            shiftDown(array, array.length - i - 1, 0);
        }
    }
    private static void shiftDown(long[] array, int size, int index) {
        while (2 * index + 1 < size) {
            int maxIdx = 2 * index + 1;
            int right = maxIdx + 1;
            if (right < size && array[right] > array[maxIdx]) {
                maxIdx = right;
            }
            if (array[index] >= array[maxIdx]) {
                return;
            }
            swap(array, index, maxIdx);
            index = maxIdx;
        }
    }
    private static void createBigHeap(long[] array) {
        // 从最后一个元素的双亲开始
        for (int i = (array.length - 2) / 2; i >= 0; i--) {
            shiftDown(array, array.length, i);
        }
    }
    private static void swap(long[] array, int i, int j) {
        long t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

七、归并排序(Merge Sort)

1.原理

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

2.实现代码

public static void mergeSort(long[] array) {
        mergeSortRange(array, 0, array.length);
    }
    //这里的 [from, to) 是左闭右开来表示区间的
    private static void mergeSortRange(long[] array, int from, int to) {
        int size = to - from;
        if (size <= 1) {
            return;
        }
        int mid = from + (size / 2);    
        //优先对左 [from, mid) 和右 [mid, to) 两个小区间先进行排序(使用同样的方式处理:分治思想)
        mergeSortRange(array, from, mid);
        mergeSortRange(array, mid, to);        
        //有了两个分别各自有序的小区间 [from, mid) 和 [mid, to)
        //通过一定的方式,将 [from, mid) [mid, to) 合并到 [from, to) 都是有序的
        //两个有序数组区间合并到一个有序数组区间(需要结果放回原地去)
        merge(array, from, mid, to);
    }
    private static void merge(long[] array, int from, int mid, int to) {
        // 先计算出来额外空间需要多个,计算两个区间加起来多少个元素
        int size = to - from;
        // 申请一个额外的数组作为临时保存的地方
        long[] other = new long[size];
        int left = from;    // 左边小区间的下标
        int right = mid;    // 右边小区间的下标
        int dest = 0;       // 临时空间的下标
        // 只要左右两个小区间还有元素要参与比较
        while (left < mid && right < to) {
            if (array[left] <= array[right]) {
                other[dest++] = array[left++];
            } else {
                other[dest++] = array[right++];
            }
        }
        // 其中一个区间的元素取完了,另一个区间里一定还有元素,再把剩余的元素,统统放入 other
        while (left < mid) {
            other[dest++] = array[left++];
        }
        while (right < to) {
            other[dest++] = array[right++];
        }
        // 把 other 中的有序元素,复制回 array 中,要注意下标的问题
        for (int i = 0; i < size; i++) {
            array[from + i] = other[i];   
        }
    }

八、桶排序(Bucket Sort)

桶排序属于计数排序的升级强化版,同时利用了分治的思想,将待排数据划分到一定数量的有序的桶里,然后再对每个桶中的数据进行排序(桶排序的稳定性取决于桶内排序算法是否稳定),最后再将各个桶里的数据有序的合并到一起。最理想的情况下,输入数据可以被均匀的分配在每一个桶中,时间复杂度可以降到O(n);最坏的情况为所有数据在同一个桶中进行排序,且使用了复杂度较高的排序算法,此时时间复杂度会变为O(n²)。为了使桶排序更加高效,需要做到以下两点:①在额外空间充足的情况下,尽量增加桶的数量。②使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值