排序算法总结

排序算法1.排序算法概括冒泡排序选择排序插入排序希尔排序归并排序快速排序堆排序计数排序桶排序基数排序删除线格式2.排序算法详细2.1冒泡排序冒泡排序是一种简单的排序算法,它重复的走访过要排序的数列,一次比较两个元素,如果他们的书序错误就把他们交换过来。...
摘要由CSDN通过智能技术生成

排序算法

https://visualgo.net/演示部分基础算法

1.排序算法概括

冒泡排序
选择排序
插入排序
希尔排序
归并排序
快速排序
堆排序
计数排序
桶排序
基数排序

2.排序算法详细

2.1 冒泡排序

冒泡排序是一种简单的排序算法,它重复的走访过要排序的数列,一次比较两个元素,如果他们的书序错误就把他们交换过来。
buddlesort

/**
     * 冒泡排序
     * 有缺陷,这种情况下在最优的情况下是O(n^2)
     * @param array
     * @return
     */
    public int[] buddleSort(int[] 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+1]){
                    int temp = array[j+1];
                    array[j+1] = array[j];
                    array[j] = temp;
                }
            }
        }
        return array;
    }

最佳情况 O(n)
最差情况 O(n^2)
平均情况 O(n^2)
空间复杂度O(1)

2.2 选择排序

选择排序是表现最稳定的排序算法之一,无论什么数据进去都是O(n^2)的时间复杂度,用的时候,数据规模越小越好。不占用额外的内存空间。
原理:每趟找出最小的或者最大的,放到相应位置,重复n-1次;
selectionSort

/**
     * 选择排序 ASC
     * 
     * @param array
     * @return
     */
    public static int[] selectionSort(int[] array) {
        if (array.length == 0)
            return array;
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i; j < array.length; j++) {
                if (array[minIndex] > array[j])
                    minIndex = j;
            }
            int temp = array[minIndex];
            array[minIndex] = array[i];
            array[i] = temp;
        }
        return array;
    }

最佳情况 O(n^2)
最差情况 O(n^2)
平均情况 O(n^2)
空间复杂度O(1)

2.3 插入排序

插入排序排序的思想是确定一部分已经确定顺序的,然后拿一个数值来进行比较插入,使其部分有序,然后扩展到整体有序。
insertionSort

 /**
     * 插入排序
     * @param array
     * @return
     */
    public static int[] insertionSort(int[] array) {
        if (array.length == 0)
            return array;
        for (int i = 0; i < array.length-1; i++) {
            if (array[i + 1] < array[i]) {  
                int j = i+1;   
                while(j != 0 && array[j - 1] > array[j] ){ 
                    int temp = array[j - 1];
                    array[j - 1] = array[j];
                    array[j] = temp;
                    --j;
                }
            }
        }
        return array;
    }

最佳情况 O(n)
最差情况 O(n^2)
平均情况 O(n^2)
空间复杂度O(1)

2.4 希尔排序

希尔排序是建立在插入排序上的,插入排序每次只能将数据移动一位,比较低效,为了提升效率,采用分组进行排序。

用语言来解释一下希尔排序的想法:
确定增量,分组,进行插入排序
如何分组呢?五个数(1 2 3 4 5)来讲的话 gap=2
3-5
x=3 3compare3-2=1 insert
x=4 4compare4-2=2 insert
x=5 5compare5-2=3 insert

gap=2/2=1

x=2 2compare2-1=1 insert(此时1-2有序)
x=3 3compare(1-2) insert(此时1-3有序)
x=4 3compare(1-3) insert(此时1-4有序)
x=5 3compare(1-4) insert(此时1-5有序)

https://www.cnblogs.com/onepixel/articles/7674659.html(从这个博客拿的图片 侵删)
在这里插入图片描述

    /**
     * 希尔排序
     * 默认采用第一次增量为length/2
     * ASC
     * @param array
     * @return
     */
    public static int[] ShellSort(int[] array){
        if (array.length == 0)
            return array;
        int gap = array.length/2;
        while(true){
            gap /= 2;
            for(int i = gap; i<array.length; i++){
                int j = i;
                int current = array[i];
                while(j-gap>=0 && current<array[j-gap]){
                    array[j] = array[j-gap];
                    j = j-gap;
                }
                array[j] = current;
            }
            if(gap==1){
                return array;
            }
        }   
    }

时间复杂度取决于gap的值
空间复杂度O(1)

2.5 归并排序

归并排序采用分治法,将已有序列的子序列进行合并得到完全有序的序列。若将两个有序表合并成一个有序表,称为2-路归并。
在这里插入图片描述

    /**
     * 归并排序
     * 默认采用2-路归并
     * @param array
     * @return
     */
    public static int[] MergeSort(int[] array){
        if (array.length == 0)
            return array;
        int gap=2;
        while(gap<=array.length){
            for(int i=0; i+gap<array.length; i+=gap){
                if(i+gap-1>=array.length-1){
                    Merger(array, i, i+gap-1, array.length-1);
                }else{
                    Merger(array, i, i+gap/2-1, i+gap-1);
                }
            }
            gap*=2;
        }
        return array;
    }
    /**
     * 归并操作
     * @param data
     * @param low
     * @param mid
     * @param high
     * @return
     */
    public static int[] Merger(int data[], int low, int mid, int high){
        int[] temp = new int[data.length];
        int i=low;
        int start=low;
        int j=mid+1;
        while(i<=mid && j<=high){
            if(data[i]<data[j]){
                temp[start++]=data[i++];
            }else{
                temp[start++]=data[j++];
            }
        }
        while(i<=mid){
            temp[start++]=data[i++];
        }
        while(j<=high){
            temp[start++]=data[j++];
        }
        while(low<=high) {
            data[low]=temp[low];
            low++;
        }
        return data;
    }

时间复杂度取决于取决于几路归并,二路归并的复杂度为O(log2^n)
空间复杂度O(n)

2.6 快速排序

快排算法是标定一个点位,比他小的放一边,大的放另外一边。
在这里插入图片描述

    /**
     * 快排
     * @param array
     * @return
     */
    public static int[] QuickSort(int[] array) {
        if(array.length==0){
            return array;
        }
        Stack<Integer> stack=new Stack<Integer>();
        stack.push(0);
        stack.push(array.length);
        while(!stack.empty()){
            int right = stack.pop();
            int left = stack.pop();
            int index=Partition(array, left, right);
            if((index-1)>left){
                stack.push(left);
                stack.push(index);
            }
            if((index+1)<right){
                stack.push(index+1);
                stack.push(right);
            }
        }
        return array;
    }
    /**
     * 快排第一次划分操作
     * @param data
     * @param low
     * @param high
     * @return
     */
    public static int Partition(int data[], int low, int high){
        int index=low;
        low=index+1;
        for(int x=index+1; x<high; x++){
            if(data[x]<data[index]){
                Swap(data, x, low);
                low++;
            }
        }
        Swap(data, index, low-1);    
        index=low-1;
        return index;
    }

最佳情况 O(n)
最差情况 O(n^2)
平均情况 O(log2^n)
空间复杂度O(1)

2.7 堆排序

堆排序是指利用堆这一数据结构进行的选择排序。
堆是具有以下性质的完全二叉树:每个结点的值都大于或者等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或者等于其左右孩子结点的值,称为小顶堆。
在这里插入图片描述
如图所示为一个大顶堆。
对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子。
在这里插入图片描述
该数组从逻辑上来讲是一个对结构,用简单的公式描述一下堆的定义就是
大顶堆:arr[i] >= arr[2i+1]&&arr[i]>=arr[2i+2]
小顶堆:arr[i] <= arr[2i+1]&&arr[i]<=arr[2i+2]
建立堆
在这里插入图片描述
堆排序本质上是一个个建立堆的过程,每成功建立一次之后,就会有最值出现,经过交换,将最值调整到末尾,然后在经过堆的建立得到第二大第三大的值,通过交换,使其序列有序。`

    /**
     * 构建堆
     * @param data
     */
    public static void buildHeap(int data[]) {
        for(int i=data.length/2-1; i>0; i--){
            adjust(data, i);
        }
    }

    /**
     * 调整操作 堆排序
     * @param data
     * @param location
     * @return
     */
    public static void adjust(int data[],int location) {
        int temp=data[location];
        for(int k=location*2+1; k<data.length; k=2*k+1){
            if(k+1<data.length&& data[k]<data[k+1]){
                k++;
            }
            if(data[k]>temp){
                data[location]=data[k];
                location=k;
            }else{
                break;
            }   
        }
        data[location]=temp;
    }
    /**
     * 堆排序
     * 大顶堆
     * @param array
     * @return
     */
    public static void HeapSort(int[] array) {
        buildHeap(array);
        for(int j=array.length-1; j>0; j--){
            Swap(array, 0, j);
            adjust(array, j );
        }
    }

构建初始堆的复杂度为O(n)
需要构建n次 由于每次n的规模都在缩小
所以比nlogn小
近似看做O(nlogn)

2.8 计数排序

计数排序先找到最大值,然后用从最小值到最大值的一个空间,用下标来代替数据进行数据的存储。
在这里插入图片描述

    /**
     * 计数排序
     * @param array
     * @return
     */
    public static int[] CountingSort(int[] array) {
        int max=0;
        for(int x=0;x<array.length;x++){
            if(array[x]>max){
                max=array[x];
            }
        }
        int[] temp = new int[max+1];
        for(int x=0;x<array.length; x++){
            System.out.println(array[x]);
            temp[array[x]]+=1;
            
        }
        return temp;
    }

计数排序时间复杂度为O(k+n)
空间复杂度为O(k+n)

2.9 桶排序

桶排序是将待排序集合中处于同一个至于的元素存入同一个桶中,也就是根据元素值特性将集合拆分为多个区域,则拆分后形成的多个桶,从至于上看是处于有序状态的。对每个桶中的元素进行排序,则所有桶中元素构成的集合是已排序的。
桶排序的过程的主要在于两点,一是元素值域的划分,如何能够合理的分块,映射规则的设定应该如何设定?二是桶内排序算法的选择,不同的排序算法会导致桶排序的复杂度和稳定性不同。

    /**
     * 划分方式的不同和内部排序算法的不同会导致桶排序的不同
     * 本次划分方式用间隔array.length来进行桶的划分
     * 内部用的array.sort 底层为Timsort
     * @param array
     * @return
     */
    public static int[] BucketSort(int[] array){
        int max=0,min=0;
        for(int i=0; i<array.length; i++){
            if(array[i]>max) max=array[i];
            if(array[i]<min) min=array[i];
        }
        //计算桶的数量
        int bucketNum = (max-min)/array.length+1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for(int i=0; i<bucketNum; i++){
            bucketArr.add(new ArrayList<Integer>());
        }
        //将每个元素放入桶中
        for(int i=0; i<array.length; i++){
            int num = (array[i]-min)/array.length;
            bucketArr.get(num).add(array[i]);
        }
        //对每个桶进行排序
        for(int i=0;i<bucketArr.size();i++){
            Collections.sort(bucketArr.get(i));
        }
        //输出
        int index=0;
        for(int i=0; i<bucketArr.size();i++){
            for(int j=0;j<bucketArr.get(i).size();j++){
                array[index++]=bucketArr.get(i).get(j);
            }
        }
        return array;
    }

时间复杂度取决于装入N个桶,每个桶进行logM排序(采用timsort排序,如果采用其他排序时间复杂度不一样),时间复杂度为O(NLogM)
空间复杂度 O(N+M)

2.10 基数排序

基数排序采用了桶排序的思想,换分成0-9十个桶,然后根据个位十位百位以此类推来进行排序。

    /**
     * 基数排序
     * @param array
     * @return
     */
    public static int[] RadixSort(int[] array){
        //计算桶的数量
        int bucketNum = 10;
        //找最大值
        int max=0,size=0;
        for(int i=0;i<array.length;i++){
            if(array[i]>max) max=array[i];
        }
        //找位数
        while (max>0){
            max/=10;size++;//求取这个最大值的位数,依次除以10;直到为0;
        }
        //x代表位数
        int x=10;
        for(int i=0;i<size;i++){
            ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
            for(int p=0; p<bucketNum; p++){
                bucketArr.add(new ArrayList<Integer>());
            }
            if(i==0){
                for(int j=0;j<array.length;j++){
                    int temp=array[j]%x;
                    bucketArr.get(temp).add(array[j]);
                }
            }else{
                for(int j=0;j<array.length;j++){
                    int temp=array[j]/(x*i)%x;
                    bucketArr.get(temp).add(array[j]);
                }
            }
            //输出
            int index=0;
            for(int z=0; z<bucketArr.size();z++){
                for(int j=0;j<bucketArr.get(z).size();j++){
                    array[index++]=bucketArr.get(z).get(j);
                }
            }
        }
        return array;
    }

时间复杂度为O(k*n)
空间复杂度为O(n+k)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值