核心的排序算法

正如看JAVA从入门到精通一样,总有些常规和核心的,而前面的插入、选择、冒泡排序都是简单的排序方法,算不上实用排序.真正体现计算机优势的排序算法正是,归并,快速,堆排序.

插入,选择、冒泡,时间复杂度都为O(n^2),空间复杂度都是O(1)。

而归并、快速、堆排序时间复杂度都为O(N*logN)   空间复杂度,归并是O(N)快速是O( logN) 堆O(1)

归并排序:

/**
 * 〈一句话功能简述〉<br>
 * 〈合并排序〉
 *
 * @author Administrator
 * @create 2019/4/26
 * @since 1.0.0
 */
public class MergerSort {
    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        mergeSort(arr , 0 , arr.length - 1);
    }

    public static void mergeSort(int[] arr , int leftbit , int rightbit) {
        if (leftbit == rightbit) return;
        int mid = leftbit + ((rightbit - leftbit) >> 1);//分成左和右两部分
        mergeSort(arr , leftbit , mid);//递归调用,流程是一样的,唯一的不同在于处理数据的范围不同
        mergeSort(arr , mid + 1 , rightbit);
        merge(arr , leftbit , mid , rightbit);
    }

    public static void merge(int[] arr , int leftbit , int mid , int rightbit) {
        int temp[] = new int[rightbit - leftbit + 1];
        int i = 0;
        int p1 = leftbit;
        int p2 = mid + 1;
        while (p1 <= mid && p2 <= rightbit) {//外排序,两个要么p1动,要么p2动一下,排到最后,总会有一个越界
            temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        //有且必有一个越界,才会有下面的两个while
        while (p1 <= mid) temp[i++] = arr[p1++];
        while (p2 <= rightbit) temp[i++] = arr[p2++];
        //将排好序的temp拷贝到arr,注意,不同递归间范围是不同的,所以是arr[]里是leftbit+i
        for (i = 0; i < temp.length; i++) arr[leftbit + i] = temp[i];
    }

归并排序的应用,小和问题:为什么用归并排序可以实现小和的计算呢?因为归并排序体现的求小和问题的过程,其实,所有的算法问题都是建立在物理过程中的,写算法代码过程是把重复的东西交给计算机去处理,代码只是给出个开始,条件,结束就可以了。

/**
 * 〈一句话功能简述〉<br>
 * 〈最小左子列和问题〉
 *
 * @author Administrator
 * @create 2019/4/30
 * @since 1.0.0
 */
import edu.princeton.cs.algs4.StdIn;

public class smallLeftSum {
    public static int smallSum(int[] arr) {
        if (arr == null || arr.length < 2) return 0;
       return mergeSort(arr , 0 , arr.length - 1);
    }

    public static int mergeSort(int[] arr , int leftbit , int rightbit) {
        if (leftbit == rightbit) return 0;
        int mid = leftbit + ((rightbit - leftbit) >> 1);//分成左和右两部分
        //        mergeSort(arr , leftbit , mid);//递归调用,流程是一样的,唯一的不同在于处理数据的范围不同
        //        mergeSort(arr , mid + 1 , rightbit);
        //        merge(arr , leftbit , mid , rightbit);
        return mergeSort(arr , leftbit , mid) + mergeSort(arr , mid + 1 , rightbit) + merge(arr , leftbit , mid , rightbit);
    }

    public static int merge(int[] arr , int leftbit , int mid , int rightbit) {
        int temp[] = new int[rightbit - leftbit + 1];
        int i = 0;
        int p1 = leftbit;
        int p2 = mid + 1;
        int res = 0;
        while (p1 <= mid && p2 <= rightbit) {//外排序,两个要么p1动,要么p2动一下,排到最后,总会有一个越界
            res+=arr[p1]<arr[p2]?arr[p1]*(rightbit-p2+1):0;
            temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        //有且必有一个越界,才会有下面的两个while
        while (p1 <= mid) temp[i++] = arr[p1++];
        while (p2 <= rightbit) temp[i++] = arr[p2++];
        //将排好序的temp拷贝到arr,注意,不同递归间范围是不同的,所以是arr[]里是leftbit+i
        for (i = 0; i < temp.length; i++) arr[leftbit + i] = temp[i];
        return res;
    }
    public static void main(String[] args){
        int num=0;
        System.out.println("请输入要排序的数量:");
        num=StdIn.readInt();
        int[] arr=new int[num];
        System.out.println("请输入要排序的数列:");
        for(int i=0;i<num;i++)arr[i]=StdIn.readInt();
        System.out.println(smallSum(arr));
    }
}

快排:其实是经典快速排序 工程上最常用的排序算法,也是实际中表现最好的排序算法,即拿最后一个数作为比较数(baseCase数),小于它的放左,大于它的放右边.."没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。"正如前辈所说,知识要及时的归纳,否则一文不值!

从仿真理解递归过程:遇到递归,可以当作一个单独的过程或函数来处理.执行完后,再处理另一个递归的过程.递归前的语句是可以被两个递归重载的.实际的运行就是这样的.

写算法,一般至少可以分成两个,一个是针对数据(逻辑),另一个是针对动作(业务).如patition就是数据(具体的实现),而QickSort就是个动作业务.

/**
 * 〈一句话功能简述〉<br>
 * 〈快排经典排法〉
 *
 * @author Administrator
 * @create 2019/5/11
 * @since 1.0.0
 */
public class QuickSort {
    public static int[] partition(int[] arr , int leftbit , int rightbit) {
        int less = leftbit - 1;
        int more = rightbit;
        while (leftbit < more) {
            if (arr[leftbit] < arr[rightbit]) swap(arr , ++ less , leftbit++);//小于,就与小于区边界扩一位与left交换后,left往下走
            else if (arr[leftbit] > arr[rightbit]) swap(arr , -- more , leftbit);//大于,left不动,大于区向左扩一位。
            else leftbit++;//等于,不交换,left向右扩一位
        }
        swap(arr , more , rightbit);//将大于区边界与最后比较数交换,这样相等 的就放在中间了
        return new int[]{less + 1 , more};//返回less+1 more值数组的第一个值与第二个值其实是等于区的左右边界
    }

    public static void swap(int[] arr , int i , int j) {
        int temp;
        temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void QickStort(int[] arr , int leftbit , int rightbit) {
        if (leftbit < rightbit) {
            swap(arr , leftbit+(int) (Math.random() * (rightbit - leftbit + 1)) , rightbit);//随便找一个数放到最后的位置,保证时间复杂度logN
            int[] p = partition(arr , leftbit , rightbit);
            QickStort(arr , leftbit , p[0] - 1);//重排从最左到小于区
            QickStort(arr , p[1] + 1 , rightbit);//大于区包含了比较数,所以要向右扩一位
        }
    }

    public static void QickStort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        QickStort(arr , 0 , arr.length - 1);
    }

堆排序,在工程上用的不多,主要是理解堆,堆太重要了,这是个算法上或数据结构的堆结构,而不是堆栈的堆。终于把核心的排序算法都搞完了。此次收获是:计算机的数据结构如树,真正的提高了工作计算效率,并且会在实际生活中被应用。这才是学算法和数据结构最重要的意义。这些都是建立在前人大量研究的基础上的,所以算法一定是搞懂,搞会。

/**
 * 〈一句话功能简述〉<br>
 * 〈堆排序〉
 *
 * @author Administrator
 * @create 2019/5/13
 * @since 1.0.0
 */
public class HeapSort {
    public static void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 0; i < arr.length - 1; i++) {
            HeapInsert(arr , i);//构建大根堆,脑补堆结构,左孩子是数据组下标 2*i+1  右孩子2*i+2  父结点 (i-1)/2
        }
        int HeapSize = arr.length;
        swap(arr , 0 , -- HeapSize);//交换堆顶与最后一个数
        while (HeapSize > 0) {
            Heapify(arr , 0 , HeapSize);//重构大根堆,过程是寻找左右孩子节点中较大的与堆顶比较,向下交换的过程
            swap(arr , 0 , HeapSize--);
        }
    }

    public static void HeapInsert(int[] arr , int index) {
        //int fatherNode = (index - 1) / 2;
        while (arr[(index - 1) / 2] < arr[index]) {
            swap(arr , (index - 1) / 2 , index);
            index = (index - 1) / 2;
        }
    }

    public static void Heapify(int[] arr , int index , int size) {
        int left = 2 * index + 1;
        //        while (index > 0) {
        //            int largerst = arr[left] > arr[left + 1] ? left : left + 1;
        //            if(arr[index]<arr[largerst])swap(arr,index,largerst);
        //        }
        while (left < size) {

            int largst = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//此处的left+1大于size的话,将问号left+1&&共同作为判断的条件 表达式转成if else的结构的话,相当于是执行的else 所以largst执行的是left
            largst = arr[largst] > arr[index] ? largst : index;
            if (largst == index) break;
            swap(arr , largst , index);
            index = largst;//与下同
            left = 2 * index + 1;//父下标统一下移,比较下组的二叉树
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值