各种排序算法性能比较

插入排序包括直接插入排序、希尔排序

1、直接插入排序:

如何写成代码:

  首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用插入。

  设定插入数和得到已经排好序列的最后一个数的位数。insertNum和j=i-1。

  从最后一个数开始向前循环,如果插入数小于当前数,就将当前数向后移动一位。

  将当前数放置到空着的位置,即j+1。

代码实现如下:

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class InsertSortDirectly {
    public static void insertSort(int[] a){
        int length = a.length; //求取出length是为了提高速度
        int insertNum ;
        for(int i=1;i<length;i++){//要插入的数
            insertNum = a[i];
            int j = i-1;
            while(j>=0&&insertNum<a[j]){
                a[j+1] = a[j];
                j--;
            }
            //比如3 6 5,此时找到j为3,则在j+1的位置插入5。
            a[j+1]=insertNum;
        }
    }

    public static void main(String[] args) {
        int[] a= {3,6,5};
        insertSort(a);
        System.out.println(Arrays.toString(a));
    }
}

  直接插入排序,最好的情况是数据元素已经全部排好序,那么内循环次数为0,外循环次数为n-1,所以,最好的情况下时间复杂度为O(N)。最坏的情况是原始数据元素集合反序排列,此时,算法中内层while循环的循环次数每次均为i。因此,最坏的情况下时间复杂度为O(N^2)。直接插入排序的空间复杂度为O(1),显然直接插入排序是一种稳定的排序算法。

 2、希尔排序:

          

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class SheelSort {
    public static void SheelSort(int[] a){
        int d = a.length;
        while(d!=0){
            d = d/2;
            for(int x = 0; x < d; x++){//分的组数
                for(int i=x+d; i<a.length; i=i+d){//组中的元素,从第2个开始
                    int j = i-d; //j为有序序列最后一位的位数
                    int temp = a[i]; //要插入的元素
                    for(; j>=0&&temp<a[j]; j=j-d){
                        a[j+d] = a[j];//向后移动d位
                    }
                    a[j+d] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] a ={592,401,874,141,348,72,911,887,820,283};
        SheelSort(a);
        System.out.println(Arrays.toString(a));
    }
}

  希尔排序虽然用了四重循环,但是其实前两层的循环次数很少,后两层就是直接插入排序,由于希尔排序小组内数据基本有序,因此内部的直接插入排序很快就排好。所以,希尔排序的时间复杂度为O(nlbn),空间复杂度为O(1),由于希尔排序算法是按增量分组进行的排序,所以,希尔排序是一种不稳定的排序算法。如5,1,1,5,如果采用步长为2,则两个1相对位置进行了交换。

 选择排序包括直接选择排序堆排序。

3、直接选择排序

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class SelectSortDirectly {
    public static void selectSort(int[] a){
        int len = a.length;
        int minIndex,temp;
        for(int i=0;i<len-1;i++){
            minIndex = i;
            for(int j=i+1;j<len;j++){
                if(a[j]<a[minIndex]){
                    minIndex = j;
                }
            }
            temp = a[i];
            a[i] = a[minIndex];
            a[minIndex] = temp;
        }
    }

public static void main(String[] args) {
    int[] a ={592,401,874,141,348,72,911,887,820,283};
    selectSort(a);
    System.out.println(Arrays.toString(a));
    }
}

  直接选择排序的时间复杂度是O(N^2),空间复杂度是O(1),它是一种不稳定的排序算法。比如2 2 2 1,这样选出最小数1和第一个2交换,那么2的相对位置发生了改变。如果在选出最小记录后,将它前面的无序记录依次后移,然后再将最小记录放在有序区的后面,这样就能保证排序算法的稳定性。

4、堆排序

  对简单选择排序的优化。

  将序列构建成大顶堆。

  将根节点与最后一个节点交换,然后断开最后一个节点。

  重复第一、二步,直到所有节点断开。

  堆排序关键要理解,从下往上,调整节点,比如说,这棵树一共3层,那么将第2层的树作为根节点,保证它的子节点都小于它,此时,如果调整第1层,若其左节点是最大值,必然会将第一层根节点和左节点进行交换,以保证第1层满足最大堆的结构,但此时,有可能会破坏第1层的左节点的最大堆结构,因此需要对这个第1层的左节点的堆进行重新调整。-------------这是关键要理解的地方!

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class HeapSort {
    public HeapSort(){
    } 

    public static void heapSort(int[] a){
        System.out.println("开始排序");
        int arrayLength=a.length;
        //循环建堆
        for(int i=0;i<arrayLength-1;i++){
            //建堆
            buildMaxHeap(a,arrayLength-1-i);
            //交换堆顶和最后一个元素
            swap(a,0,arrayLength-1-i);
        }
    } 

    private static void swap(int[] data, int i, int j) {
        //TODO Auto-generated method stub
        int tmp=data[i];
        data[i]=data[j];
        data[j]=tmp;
    } 

    //对data数组从0到lastIndex建大顶堆
    private static void buildMaxHeap(int[] data, int lastIndex) {
        //从lastIndex处节点(最后一个节点)的父节点开始 

        for(int i=(lastIndex-1)/2;i>=0;i--){
            //k保存正在判断的节点
            int k=i;
            //如果当前k节点的子节点存在
            while(k*2+1<=lastIndex){
                //k节点的左子节点的索引
                int biggerIndex=2*k+1;
                //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
                if(biggerIndex<lastIndex){
                    //若果右子节点的值较大
                    if(data[biggerIndex]<data[biggerIndex+1]){
                        //biggerIndex总是记录较大子节点的索引
                        biggerIndex++;
                    }
                } 

                //如果k节点的值小于其较大的子节点的值
                if(data[k]<data[biggerIndex]){
                    //交换他们
                    swap(data,k,biggerIndex);
                    //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
                    //如果不理解,那么请使用打断点的方式来运行,则可发现,当i=0时,由于节点1和节点0发生了交换,因此需要重新调整1节点的堆结构,保证
                    //1节点的值仍然大于其左右节点的值
                    k=biggerIndex;
                }else{
                    break;
                }
            }
        }
} 

    public static void main(String[] args) {
        int a[] = {7,13,6,43,5,23,4};
        heapSort(a);
        System.out.println(Arrays.toString(a));
    }
}

  堆排序算法是基于完全二叉树的排序,其时间复杂度是O(nlbn),其空间复杂度是O(1),堆排序是一种不稳定的排序算法,比如5 5 5,这样,构建好最大堆后,第1个5和最后一个5要进行交换,因此,堆排序是一种不稳定的排序算法。

  利用交换数据元素的位置进行排序的方法是交换排序。常用的交换排序有冒泡排序和快速排序。快速排序是一种分区交换排序方法。

5、冒泡排序

  将序列中所有元素两两比较,将最大的放在最后面。

  将剩余序列中所有元素两两比较,将最大的放在最后面。

  重复第二步,直到只剩下一个数。

如何写成代码:

  设置循环次数。

  设置开始比较的位数,和结束的位数。

  两两比较,将最小的放到前面去。

  重复2、3步,直到循环次数完毕。

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class BubbleSort {
    public static void bubbleSort(int[] a){
        boolean isSorted = true;
        for(int i=0;i<a.length-1&&isSorted;i++){
            isSorted = false;
            for(int j=0;j<a.length-1-i;j++){
                if(a[j]>a[j+1]){
                    int temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                    isSorted = true;//内循环如果发生了交换,则证明还在继续排序
                }
            }
            //如果经过1趟就已经排序完毕,那么第2趟结束后,isSorted = false; ,此时,
            //外循环可以根据isSorted的标记状态提前结束。
        }
    }

    public static void main(String[] args) {
        int[] a ={592,401,874,141,348,72,911,887,820,283};
        bubbleSort(a);
        System.out.println(Arrays.toString(a));
    }
}

  冒泡排序的时间复杂度是O(n^2),空间复杂度为O(1),冒泡排序是一种稳定的排序算法。

快速排序是一种二叉树结构的交换排序方法。

6、快速排序

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class QuickSort {
/**
* 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
*
* @param numbers 带查找数组
* @param low 开始位置
* @param high 结束位置
* @return 中轴所在位置
*/
    public static int getMiddle(int[] numbers, int low,int high){
        int temp = numbers[low]; //数组的第一个作为中轴
        while(low < high){
            while(low < high && numbers[high] > temp){
                high--;
            }
            if(low<high){
                numbers[low++] = numbers[high];//强制塞值并向前移一位
            }
            while(low < high && numbers[low] < temp){
                low++;
            }
            if(low<high){
                numbers[high--] = numbers[low] ; //强制塞值并向前移一位
            }
        }
        numbers[low] = temp ; //中轴记录到尾
        return low ; // 返回中轴的位置
    }

/**
*
* @param numbers 带排序数组
* @param low 开始位置
* @param high 结束位置
*/
    public static void quickSort(int[] numbers,int low,int high){
        if(low < high){
            int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
            quickSort(numbers, low, middle-1); //对低字段表进行递归排序
            quickSort(numbers, middle+1, high); //对高字段表进行递归排序
        }
    }

/**
* 快速排序
* @param numbers 带排序数组
*/
    public static void quick(int[] numbers){
        if(numbers.length > 0){ //查看数组是否为空{
            quickSort(numbers, 0, numbers.length-1);
        }
    }

    public static void main(String[] args) {
        int a[] = {6,7,18,5,3,12};
        quick(a);
        System.out.println(Arrays.toString(a));
    }
}

  快速排序如果每次选取的标准元素都能均分两个子数组区间长度,这样的快速排序过程是一个完全二叉树结构。最好情况下快速排序算法时间复杂度是O(nlbn)。快速排序最坏的情况是,数据元素已经全部有序,此时数组根节点的分解次数构成一颗二叉退化树,所以,最坏情况下快速排序算法的时间复杂度是O(n^2)。

  由于快速排序算法需要堆栈空间临时保存递归调用参数,堆栈空间的使用个数和递归调用的次数有关,由于二叉树有可能是单支二叉树,而单支二叉树的深度为n-1,所以,最坏情况下快速排序算法的空间复杂度是O(n)。

 7、归并排序

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

public class MergeSort {
/**
* 归并排序
* 简介:将两个(或两个以上)有序表合并成一个新的有序表 即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列
* 时间复杂度为O(nlogn)
* 稳定排序方式
* @param nums 待排序数组
* @return 输出有序数组
*/
    public static int[] sort(int[] nums, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            //左边
            sort(nums, low, mid);
            //右边
            sort(nums, mid + 1, high);
            //左右归并
            merge(nums, low, mid, high);
        }
        return nums;
    } 

    public static void merge(int[] nums, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指针
        int j = mid + 1;// 右指针
        int k = 0; 

        //把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
            }
        } 

        //把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = nums[i++];
        } 

        //把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = nums[j++];
        } 

        //把新数组中的数覆盖nums数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }
    } 

//归并排序的实现
    public static void main(String[] args) {
        int[] nums = { 2, 7, 8, 3, 1, 6, 9, 0, 5, 4 };
        MergeSort.sort(nums, 0, nums.length-1);
        System.out.println(Arrays.toString(nums));
    }
}

  归并排序的时间复杂度是O(nlbn),由于归并排序使用了n个临时内存单元存放数据元素,所以,归并排序算法的空间复杂度是O(n)。

  归并排序是一种稳定的排序算法。前面的几个时间复杂度是O(nlbn)的排序算法都是不稳定的排序算法,而归并排序算法不仅时间复杂度是O(nlbn),而且还是一种稳定的排序算法。这是归并排序算法的最大特点。

8、基数排序

  基数排序,因为要求进出桶中的数据元素要满足先入先出的原则,因此,这里所说的桶其实就是队列。

package zhouls.bigdata.DataFeatureSelection;

import java.util.Arrays;

/*
* 对于一个int数组,请编写一个基数排序算法,对数组元素排序。
* 给定一个int数组A及数组的大小n,请返回排序后的数组。保证元素均小于等于2000。
*
测试样例:
[1,2,3,5,2,3],6
[1,2,2,3,3,5]
*/

public class RadisSort {
    //各位装通法
    public static int[] radixSort(int[] A, int n) {
        //首先确定排序的趟数;
        int max=A[0];
        for(int i=1;i<n;i++){
            if(A[i]>max){
                max=A[i];
            }
        }
        int time=0;
        //判断位数;
        while(max>0){
            max/=10;
            time++;
        }
        int length = n;
        int divisor = 1;// 定义每一轮的除数,1,10,100...
        int[][] bucket = new int[10][length];// 定义了10个桶,以防每一位都一样全部放入一个桶中
        int[] count = new int[10];// 统计每个桶中实际存放的元素个数
        int digit;// 获取元素中对应位上的数字,即装入那个桶
        for (int i = 1; i <= time; i++) {// 经过4次装通操作,排序完成
            for (int temp : A) {// 计算入桶
                digit = (temp / divisor) % 10;
                bucket[digit][count[digit]++] = temp;
            }
            int k = 0;// 被排序数组的下标
            for (int b = 0; b < 10; b++) {// 从0到9号桶按照顺序取出
                if (count[b] == 0)// 如果这个桶中没有元素放入,那么跳过
                    continue;
                for (int w = 0; w < count[b]; w++) {
                    A[k++] = bucket[b][w];
                }
                count[b] = 0;// 桶中的元素已经全部取出,计数器归零
            }
            divisor *= 10;
        }
        return A;
    }

    public static void main(String[] args) {
    int a[] = {1,2,3,5,2,3};
    System.out.println(Arrays.toString(radixSort(a, a.length)));
    }
}

  基数排序时间复杂度是O(mn),m是数字的最大位数,由于基数排序算法中要m次使用n个节点临时存放n个数据元素,因此,基数排序算法的空间复杂度为O(n)。

基数排序是一种稳定的排序算法。

总结:

  排序分内部排序和外部排序两种。内部排序是指把待排数据元素全部调入内存中进行的排序。如果数据元素的数量太大,需要分批导入内存中。分批导入内存的数据元素排好序后再分批导出到磁盘的排序方法称作外部排序。两者排序算法原理很大地方都相同,但是内存中的读写速度和在外存的读写速度差别很大,所以评价标准差别很大。这里只讨论内部排序。

排序算法优劣的标准:

  1、时间复杂度。

  2、空间复杂度:算法中使用的辅助存储空间是多少。当排序算法中使用的辅助存储空间与要排序数据元素的个数n无关时,其空间复杂度为O(1)。

  3、稳定性。

各种排序算法性能比较:

  排序方法                             最好时间                    平均时间               最坏时间                       最坏辅助空间                      稳定性

  直接插入排序                       O(n)                         O(n^2)               O(n^2)                         O(1)                                 稳定

  希尔排序                             O(nlbn)                     O(nlbn)              O(nlbn)                         O(1)                                不稳定

  直接选择排序                      O(n^2)                      O(n^2)              O(n^2)                         O(1)                                不稳定

  堆排序                               O(nlbn)                      O(nlbn)              O(nlbn)                         O(1)                               不稳定

  冒泡排序                            O(n)                           O(n^2)              O(n^2)                         O(1)                                 稳定

  快速排序                            O(nlbn)                      O(nlbn)              O(n^2)                         O(n)                               不稳定

  归并排序                            O(nlbn)                      O(nlbn)              O(nlbn)                         O(n)                                 稳定

  基数排序                            O(mn)                       O(mn)                 O(mn)                          O(n)                                 稳定

原文地址:https://www.cnblogs.com/alamps/p/8473815.html

时间: 2024-10-06 02:16:09

各种排序算法性能比较的相关文章

数据结构实践——大数据集上排序算法性能的体验

本文是针对[数据结构基础系列(9):排序]的实践项目. [项目 - 大数据集上排序算法性能的体验] 设计一个函数,产生一个至少5万条记录的数据集合.在同一数据集上,用直接插入排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序等算法进行排序,记录所需要的时间,经过对比,得到对复杂度不同的各种算法在运行时间方面的感性认识. 提示1:这一项目需要整合多种排序算法,可以考虑先建设排序算法库,作为我们这门课算法库的收官之作: 提示2:本项目旨在获得对于复杂度不同算法的感性认识,由于数据分布

转:5种排序算法性能比较总结

1 概述 本文对比较常用且比较高效的排序算法进行了总结和解析,并贴出了比较精简的实现代码,包括选择排序.插入排序.归并排序.希尔排序.快速排序等.算法性能比较如下图所示: 2 选择排序 选择排序的第一趟处理是从数据序列所有n个数据中选择一个最小的数据作为有序序列中的第1个元素并将它定位在第一号存储位置,第二趟处理从数据序列的n-1个数据中选择一个第二小的元素作为有序序列中的第2个元素并将它定位在第二号存储位置,依此类推,当第n-1趟处理从数据序列的剩下的2个元素中选择一个较小的元素作为有序序列中

排序算法性能比较

算法思路 排序算法 时间复杂度 最好情况 最坏情况 空间复杂度 稳定性 插入排序 直接插入 O(n2) O(n) O(n2) O(1) 是 希尔排序 O(n(logn)2)     O(1) 否 交换排序 冒泡排序 O(n2) O(n) O(n2) O(1) 是 快速排序 O(nlogn) O(nlogn) O(n2) O(logn) 否 选择排序 直接选择 O(n2) O(n2) O(n2) O(1) 否 堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 否 归并排序 归

排序算法大集锦_各种排序算法性能比较

对10000个1-10000的随机数进行排序,并显示出运行时间 数组是用以前用VC++&MatLab生成的,比较长...哈哈,感受一下计算机的速度! #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <malloc.h> #include <time.h> int a[10000]={ 5282,330

排序算法性能及选择总结

排序法 平均时间 最坏情况 最好情况 稳定度 额外空间 备注 直接插入 O(n2) O(n2) O(n) 稳定 O(1) 大部分已排序时较好(简单) 希尔 O(nlogn) O(nlogn) 与步长相关 不稳定 O(1) n小时较好(较复杂) 冒泡 O(n2) O(n2) O(n) 稳定 O(1) n小时较好(简单) 快排 O(nlogn) O(n2) O(nlogn) 不稳定 O(logn) n大时较好,基本有序时反而不好(较复杂) 直接选择 O(n2) O(n2) O(n2) 不稳定 O(1

常见的排序算法性能对比

排序法 平均时间 最差情形 稳定度 额外空间 备注 冒泡 O(n2) O(n2) 稳定 O(1) n小时较好 交换 O(n2) O(n2) 不稳定 O(1) n小时较好 选择 O(n2) O(n2) 不稳定 O(1) n小时较好 插入 O(n2) O(n2) 稳定 O(1) 大部分已排序时较好 基数 O(logRB) O(logRB) 稳定 O(n) B是真数(0-9), R是基数(个十百) Shell O(nlogn) O(ns) 1<s<2 不稳定 O(1) s是所选分组 快速 O(nlo

排序算法系列之八大排序算法性能比较-从实验结果分析

回顾各大排序算法的实现代码: #include "stdafx.h" #include <iostream> #include <time.h> #include <vector> using namespace std; template<class T> void BubbleSort(T *x, const int N) { for(int k= N-1; k>0 ;k--) { for(int i=0; i<k; i+

Java中的数据结构及排序算法

(明天补充) 主要是3种接口:List Set Map List:ArrayList,LinkedList:顺序表ArrayList,链表LinkedList,堆栈和队列可以使用LinkedList模拟 Set:HashSet没有重复记录的集合 Map:HashMap就是哈希表 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap 数据结构参考链接

[Data Structure] 八大排序算法

排序有内部排序和外部排序之分,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存.我们这里说的八大排序算法均为内部排序. 下图为排序算法体系结构图: 1. 直接插入排序(Straight Insertion Sort ) 基本思想:将待排序的无序数列看成是一个仅含有一个元素的有序数列和一个无序数列,将无序数列中的元素逐次插入到有序数列中,从而获得最终的有序数列. 算法流程: 1)初始时, a[0]自成一个有序区, 无序区为a[1