排序——归并排序&&堆排序

86 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,[点击查看活动详情]

归并排序

mergeSort
是建立在归并操作上的。
采用分治法。将已有序的子序列合并,得到完整的有序序列
将两个有序表合并成一个有序表,称为2路归并

特点

时间复杂度:O(nlog2n)
空间复杂度:O(n)
是稳定的

代码

import java.util.Random;
public class MergeSort{
    public static void main(String[] args){
        int[] arr=new int[20];
        Random random=new Random();
        for(int i=0;i<arr.length;i++){
            arr[i]=random.nextInt(50);
        }
        mergeSort(arr,0,arr.length-1);
        System.out.println(Arrayds.toString(arr));
    }
    private static void mergeSort(int[] arr,int l,int r){
        //优先排序,如果元素较少
        if(r-l<=10){
            //改造希尔排序,使用于一个区间
            /*
                shellSort(arr,0,3)//0~3,进行排序
                public static void shellSort(int[] arr,int l,int r){
                    int len = r-l+1;
                    for(gap=len)
                    for(i<=r)
                    for(j-gap>=l)
                }
            */
            
            ShellSort.shellSort(arr,l,r);
            return;
        }
        int mid=(l+r)/2;
        //分
        mergeSort(arr,l,mid);
        mergeSort(arr,mid+1,r);
        //合
        //r如果左边的最后小于右边的最初,则没必要合并
        if(arr[mid]>arr[mid+1]){
            merge(arr,l,mid,r);
        }
        
    }
    
    private static void merge(int[] arr,int l,int mid,int r){
        int[] aux=new int[r-l+1];
        for(int i=l;i<=r;i++){
            aux[i-l]=arr[i];
        }
        int i=l;
        int j=mid+l;
        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++;
            }
        }
    }
}

堆排序

利用堆数据结构设计的算法。
堆积是一个近似完全二叉树的结构,同时满足堆积的性质。即子节点的键值或索引总小于(大于)它的父节点。
二叉堆是一颗完全二叉树。
堆中的某个结点的值不大于父节点的值——最大堆。
下层的某一元素不一定小于上层的某一元素。
既然是完全二叉树,所以可以用数组定义该结构。
父节点的角标:(i-1)/2
左孩子的角标:2i+1
右孩子的角标:2
i+2

特点

时间复杂度:O(nlog2n)
空间复杂度:s(1)
是不稳定的。

代码

public class HeapSort{
    public static void main(String[] args){
       int[] arr=new int[20];
        Random random=new Random();
        for(int i=0;i<arr.length;i++){
            arr[i]=random.nextInt(50);
        }
        
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    private static int len;
    
    private static void heapSort(int[] arr){
        len=arr.length;
        //1,将传入的数组,堆化
        heapify(arr);
        //2,将最大值与最后一个进行交换,再堆化
        for(int i=arr.length-1;i>=0;i--){
            swap(arr,0,i);
            len--;
            heapify(arr);
        }
    }
    
    private static void heapify(int[] arr){
        for(int i=len-1;i>=0;i--){
            sifDown(arr,i);
        }
        System.out.println(Arrays.toString(arr));
    }
    
    private static void sifDown(int[] arr,int k){
        while(leftChild(k)<len){
            int j = leftChild(k);
            if(j+1<len && arr[j+1]>arr[j]){
                j=rightChild(k);
            }
            if(arr[k]<arr[j]){
                swap(arr,k,j);
                k=j;
            }else{
                break;
            }
        }
    }
    
    private static void swap(int[] arr,int i,int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    
    private static int leftChild(int i){
        return i*2+1;
    }
    
    private static int rightChild(int i){
        return i*2+2;
    }
    
    private static int parent(int i){
        return (i-1)/2;
    }
}