排序算法

参考博客:https://blog.csdn.net/hellozhxy/article/details/79911867

http://www.cnblogs.com/jetpie/p/3971382.html

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;

不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;

时间复杂度: 一个算法执行所耗费的时间。

空间复杂度:运行完一个程序所需内存的大小。

算法总结:

排序算法时间复杂度空间复杂度稳定性是否占用额外内存
冒泡O(n2)O(1)稳定
插入O(n2)O(1)稳定
选择O(n2)O(1)

不稳定

希尔O(nlogn)O(1)不稳定
O(nlogn)O(1)

不稳定

快速O(nlogn)O(logn)不稳定
归并O(nlogn)O(n)稳定
基数排序O(nXk)O(n+k)稳定

 

冒泡排序法(稳定):元素两两比较,交换位置。经过一轮比较后,最大的元素会出现在最大索引处。

时间复杂度:O(n2)      空间复杂度:O(1)

算法实现:

public static int[] bubbleSort(int[] array){
        if (array.length == 0) {
            return array;
        }
        for (int j = 0; j < array.length-1; j++) {
            for (int i = 0; i < array.length - 1-j; i++) {
                if (array[i] > array[i + 1]) {
                    //交换位置
                    int temp = array[i];
                    array[i] = array[i + 1];
                    array[i + 1] = temp;
                }
            }
        }
        return array;

    }

选择排序法(不稳定):从第一个元素开始,去跟后面每一个元素进行比较,交换位置,经过一轮排序后,最小的元素会出现在最小索引处。

时间复杂度: O(n2)  空间复杂度:O(1)

算法实现:

public static int[] selectSort(int[] array){
        if(array.length==0){
            return array;
        }else for (int index = 0; index < array.length-1; index++) {
            for (int j = index+1; j <array.length ; j++) {
                if(array[index]>array[j]){//找到最小的数
                    int temp=array[index];
                    array[index]=array[j];
                    array[j]=temp;
                }
            }
        }

        return array;

    }

直接插入排序(稳定):每一次把后面一个元素插入到前一个有序列表中,插入进去后,使之仍保持有序。从第一个元素,取出下一个元素向前扫描,插到所有比他大的数前。

时间复杂度:O(n2)  空间复杂度:O(1)

算法实现:

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

快速排序法(不稳定):https://blog.csdn.net/adusts/article/details/80882649

分治法:比大小,再分区

1.从数组中取出一个数,作为基准数。

2.区:将比这个数大或等于的数全放到他的右边,小于他的数全放到他的左边。

3.再对左右区间重复第二步,直到各区间只有一个数。

元素

5

3

9

1

6

7

2

4

0

8

坑位

坑位1

 

坑位3

 

坑位5

坑位7

坑位6

坑位4

坑位2

 

 

0

 

4

 

2

5

7

6

9

 

 

K1

 

K3

 

K5

K7

K6

K4

K2

 

 

0

3

4

1

2

5

7

6

9

 

 

 

 

 

 

 

 

 

 

 

 

时间复杂度:O(nlogn) 空间复杂度:O(logn)

算法实现:

public class QuickSort {
    //start 默认是0
    //end 是数组长度-1
    public static void quickSort(int[] arr, int start, int end) {
        if (start < end) {
            //获取分区索引
            int index = getIndex(arr, start, end);
            //对左右两个分区 再进行同样的步骤 ,即是递归调用
            quickSort(arr, start, index - 1);//左半部分
            quickSort(arr, index + 1, end);//右半部分
        }
    }

    private static int getIndex(int[] arr, int start, int end) {
        int i = start;
        int j = end;
        //定义基准数
        int x = arr[i];
        //循环
        while (i < j) {
            //从右往左比较
            while (i < j && arr[j] >= x) {
                j--;
            }
            //从右往左找到比基准数小的数了后,填坑
            if (i < j) {
                //把这个数填到上一个坑位
                arr[i] = arr[j];
                //让 i++;
                i++;

            }

            //从左往右找
            while (i < j && arr[i] < x) {
                i++;
            }
            // 找比基准数大的数,找到后填坑
            if (i < j) {
                arr[j] = arr[i];
                j--;
            }
        }
        //当上面的循环结束后把基准数填到最后一个坑位,也就一基准数为界,分成了左右两部分
        arr[i] = x; //把基准数填进去
        return i; //返回基准数所在位置的索引
    }
}

归并排序(稳定):先分再合 

将每一个元素都看成是一个有序序列,两两合并。

采用分治法,将所有的子序列合并成一个完全有序的序列。

时间复杂度:O(nlogn) 空间复杂度:O(n) 

算法实现:

 public static int[] mergeSort(int[] array){
        if (array.length <2) {
            return array;
        }
        //拆分
        depart(array,0,array.length-1);
        //合并
        merge(array,0,(array.length/2)-1,array.length-1);
        return  array;
    }

    private static void depart(int[] array, int start, int end) {
        int center=(start+end)/2;
        if(start<end){
            depart(array,start,center);
            depart(array,center+1,end);
            merge(array,start,center,end);
        }
    }

    private static void merge(int[] array, int startIndex, int centerIndex, int endIndex) {
        //定义一个临时数组
        int[] tempArr=new int[endIndex-startIndex+1];
        //定义左边数组的起始索引
        int i=startIndex;
        //定义右边数组的起始索引
        int j=centerIndex+1;
        //定义临时数组的起始索引
        int index=0;
        //比较左右两个数组的元素大小往临时数组中放
        while (i<=centerIndex&&j<=endIndex){
            if(array[i]<=array[j]){
                tempArr[index]=array[i];
                i++;
            }else {
                tempArr[index]=array[j];
                j++;
            }
            index++;
        }
        //处理剩余元素
        while (i<=centerIndex){
            tempArr[index] = array[i];
            i++;
            index++;
        }
        while (j <= endIndex) {
            tempArr[index] = array[j];
            j++;
            index++;
        }
        //将临时数组中的元素放到原数组中
        for (int k = 0; k < tempArr.length; k++) {
            array[k+startIndex]=tempArr[k];
        }
    }

希尔排序(不稳定):插入排序的改进,插入排序其实就是增量为1的希尔排序

将数组按照增量X分组,每个子数组中按照插入排序。用下一个增量X/2对子数组再进行分组,直到X=1。

时间复杂度:O(nlogn) 空间复杂度:O(1)

算法实现:

public static int[] shellSort(int[] array){
        //定义一个增量

        if (array.length == 0) {
            return array;
        }
        //使用克努特序列选择增量 h=1 h=3*h+1
        int jiange=1;
       while (jiange<=array.length/3){
            jiange=jiange*3+1;
        }
        for (int h = jiange; h > 0; h=(h-1)/3) {
            for (int i = h; i < array.length; i++) {
                int j = i;
                while (j > 0 && array[j] < array[j - h]) {
                    int temp = array[j];
                    array[j] = array[j - h];
                    array[j - h] = temp;
                    j -= h;
                }
            }
        }
        return array;
    }

基数排序(稳定):不能比较有负数和0的数组,是一种非比较排序

只需要对元素进行分配与收集进行排序 按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。

时间复杂度:O(nXk)O(n+k)

代码实现:

public static int[] RadixSort(int[] array){
        if(array==null||array.length<2){
            return array;
        }
        //确定排序轮次
         //获取数组中的最大值
         int max=getMax(array);
         int len = String.valueOf(max).length();
         //定义二维数组,放10个基
         int[][] tempArr=new int[10][array.length];
         //定义统计数组
         int[] counts=new int[10];
         //循环轮次
         for (int i = 0,n=1; i < len; i++,n*=10) {
             for (int j = 0; j < array.length; j++) {
                 //获取每个位上的数字
                 int ys =array[j]/n%10;
                 tempArr[ys][counts[ys]++]=array[j];
             }
             //取出统计数组中的元素
             int index=0;
             for (int k = 0; k < counts.length; k++) {
                 if(counts[k]!=0){
                     for (int h = 0; h < counts[k]; h++) {
                         //从统计数组中取出元素放回原数组
                         array[index]=tempArr[k][h];
                         index++;
                     }
                     counts[k]=0;//清除上一次统计的次数
                 }
             }

         }
          return array;
     }

    private static int getMax(int[] array) {
         int max=array[0];
        for (int i = 1; i < array.length; i++) {
            if(array[i]>max){
                max=array[i];
            }
        }
         return max;
    }

堆排序(不稳定):堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

将待排序的数组构造成一个大顶堆,从最后一个非叶子节点开始转 最大值就是堆顶的根节点 将根节点与末尾元素互换,末尾就是最大值 将剩余的n-1个元素重新构造成一个堆,得到n个元素的次小值。重复
升序用大顶堆 arr[i]>=arr[2i+1]&&arr[i]>=arr[2i+2]

降序用小顶堆 arr[i]<=arr[2i+1]&&arr[i]<=arr[2i+2]

二叉堆:

#1 - Shape Property: 它是一个完全二叉树。

#2 - Heap Property: 主要分为max-heap propertymin-heap property(这就是我以前说过的术语,很重要)

  |--max-heap property :对于所有除了根节点(root)的节点 i,A[Parent]≥A[i]A[Parent]≥A[i]

  |--min-heap property :对于所有除了根节点(root)的节点 i,A[Parent]≤A[i]

首先将一个数组初始化成一个堆:

 

Input: 数组A

Initialization: 堆初始化

*堆的根节点(root)为A[0];

时间复杂度:O(nlogn)空间复杂度:O(1)

算法实现:

public static int[] HeapSort(int[] array){
        //定义开始调整的位置
        int startIndex=(array.length-1)/2;
        for(int i=startIndex;i>=0;i--){
            toMaxHeap(array,array.length,i);
        }
        //数组已经调整为大顶堆,调换根元素与最后一个元素
        for(int i=array.length-1;i>0;i--){
            //进行调换
            int t=array[0];
            array[0]=array[i];
            array[i]=t;
            //再把剩余元素掉换成大顶堆
            toMaxHeap(array,i,0);
        }
          return array;
    }

    /**
     *
     * @param array 要排序的数组
     * @param size 调整的元素个数
     * @param index 从哪里开始调整
     */
    private static void toMaxHeap(int[] array, int size, int index) {
        //获取左右子节点的索引
        int leftNodeIndex=index*2+1;
        int RightNodeIndex = index * 2 + 2;
        //查找最大节点所对应的索引
        int MaxIndex=index;
        if(leftNodeIndex<size&&array[leftNodeIndex]>array[MaxIndex]){
            MaxIndex=leftNodeIndex;
        }
        if (RightNodeIndex<size&&array[RightNodeIndex] > array[MaxIndex]) {
            MaxIndex = RightNodeIndex;
        }
        //调换位置,构造最大堆
        if(MaxIndex!=index){
            int temp=array[MaxIndex];
            array[MaxIndex]=array[index];
            array[index]=temp;
            //调换完之后可能影响到下面的子树不是大顶堆,需要递归
            toMaxHeap(array,size,MaxIndex);
        }
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值