zoukankan      html  css  js  c++  java
  • (纯白话算法系列)归并排序,时间复杂度分析、代码演示,堆是什么?

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

    白话说:所谓归并排序,望文生义,就是把两个东西合并在一起了,那么是什么东西合并在一起了呢?是两个已经排好序的数组进行合并到一个数组中,这两个排好序的数组分别有一个指针指向第0个元素,谁小谁放进大数组中。

    大致排序过程是这样的:
    在这里插入图片描述
    图摘自–https://www.cnblogs.com/qingmingsang/articles/5283870.html
    先把数组中的元素两两比较,创建一个辅助数组,将排好序的数字放进辅助数组中,然后再把辅助数组中的数放回原数组,然后两个合并好的数组再合并,再创建一个辅助数组,再把两个数组中排好序的数字放进辅助数组中,再把辅助数组放回原数组中,直到所有的数组全部排好序。

    看一下代码:

    package com.bean.com.bean.sortAlg;
    
    import java.util.Arrays;
    
    public class MargeSort {
        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 left, int right) {
            if(left == right) {
                return;
            }
            int mid = left + ((right - left)>>1);//等于(left+right)/2,位运算比较快
            MergeSort(arr, left, mid);//把左边的元素全拆开
            MergeSort(arr, mid+1, right);//把右边的元素全拆开
            MergeSort(arr, left, mid, right);//left~right之间排序
        }
    
        public static void MergeSort(int[] arr, int left, int mid, int right) {
            int[] help = new int[right - left + 1];//辅助数组,暂存排好序的元素
            int index = 0;
            int p1 = left;//左指针
            int p2 = mid + 1;//右指针
            while(p1 <= mid && p2 <= right) {//只要左右指针没超出范围,就排序
                help[index++] = arr[p1] > arr[p2] ? arr[p2++] : arr[p1++];
                //谁小谁先入help数组
            }
            while(p2 <= right) {//p1排完了,p2还有没排完的元素,则依次入数组
                help[index++] = arr[p2++];
            }
            while(p1 <= mid) {//p2排完了,p1继续依次扔进help数组
                help[index++] = arr[p1++];
            }
            for(int i = 0; i < help.length; i++) {
                arr[left + i] = help[i];//把排好序的元素放回原数组中!
            }
        }
        //打印数组
        public static void printArray(int[] arr) {
            if(arr == null) {
                return;
            }
            for(int i = 0; i < arr.length; i++) {
                System.out.print(arr[i]+" ");
            }
            System.out.println();
        }
        //形成随机数组
        public static int[] generateRandomArray(int maxSize, int maxNum) {
            if(maxSize <= 0) {
                return null;
            }
            int[] ranArray = new int[(int) (Math.random() * (maxSize + 1) )];
            for(int i = 0; i < ranArray.length; i++) {
                ranArray[i] = (int) (Math.random() * (maxNum + 1)) - (int) (Math.random() * maxNum);
            }
            return ranArray;
        }
        //判断两个数组是否相等
        public static boolean isEquals(int[] arr1, int[] arr2) {
            if(arr1.length != arr2.length) {
                return false;
            }
            if(arr1 == null && arr2 != null || arr1 != null && arr2 == null) {
                return false;
            }
            if(arr1 == null && arr2 == null) {
                return true;
            }
            for(int i = 0; i < arr1.length; i++) {
                if(arr1[i] != arr2[i]) {
                    return false;
                }
            }
            return true;
        }
        //完全正确的排序方法
        public static void comparator(int[] arr) {
            Arrays.sort(arr);
        }
        //复制数组
        public static int[] copyArray(int[] arr) {
            int[] newArr = new int[arr.length];
            for(int i = 0; i < arr.length; i++) {
                newArr[i] = arr[i];
            }
            return newArr;
        }
        public static void main(String[] args) {
            int testTimes = 100000;
            int maxNum = 100;
            int maxSize = 2000;
            boolean flag = true;
            for(int i = 0; i < testTimes; i++) {
                int[] arr1 = generateRandomArray(maxSize, maxNum);
                int[] arr2 = copyArray(arr1);
                comparator(arr1);
                MergeSort(arr2);
                if(!isEquals(arr1, arr2)){
                    flag = false;
                    break;
                }
            }
            System.out.println(flag ? "Nice! Nothing is wrong~" : "Ooops! Your method is wrong..");
            int[] arr1 = generateRandomArray(maxSize, maxNum);
            System.out.print("before:");printArray(arr1);
            long beforetime = System.currentTimeMillis();
            MergeSort(arr1);
            long aftertime = System.currentTimeMillis();
            System.out.println("execute time is:"+(aftertime - beforetime)+"ms");
            System.out.print("after");printArray(arr1);
        }
    }
    
    
    

    其实就是把一个数组进行拆块,每一小块都排序,然后再把两个排好序的小块整合,再进行排序,直到所有小块都排好序,整体排序结束。

    时间复杂度

    假如有N个元素,那么每次二分,它的时间复杂度是logN,但是每次二分完了还需要进行比较,比较的次数跟有多少个元素N有关,所以整体时间复杂度是O(n*logn),额外空间复杂度说的就是那个辅助数组,它每次创建完又被销毁了,所以额外的空间复杂度是O(n),但是根据内部缓存法,可以使额外空间复杂度变成O(1),比较难,所以本篇博客不作记载,如有需要请自行百度。

  • 相关阅读:
    学习笔记Jmail收发邮件
    ModalPopup
    学习笔记:UpdatePanel控件
    转AjaxControlToolkit的安装与使用详解
    转linq中的Single()、First()、Take(1) LINQ 标准的查询操作符 排序 orderby、thenby、Take
    转Global.asax文件
    转<%%>、<%=%>、<%$%>、<%@%>的区别
    C++文件包含处理—#include
    GISer学习之道(转载)
    OSG中的示例程序简介
  • 原文地址:https://www.cnblogs.com/taobean/p/12364264.html
Copyright © 2011-2022 走看看