四种排序算法比较

247 阅读7分钟

冒泡排序

冒泡排序举例说明

假设要对[4,2,7,1,3]进行排序

  • 第一步:比较4和2的值,4比2大,
  • 第二步:交换顺序4和2顺序,为[2,4,7,1,3]
  • 第三步:比较4和7,4比7小(不用交换顺序)
  • 第四步:比较7和1,7比1大
  • 第五步:交换顺序7和1顺序,为[2,4,1,7,3]
  • 第六步:比较7和3,7比3大
  • 第七步:交换顺序7和3顺序,为[2,4,1,3,7]

经过7步操作之后,我们把最大的元素[7],换到了最右边,这也是算法名为冒泡排序的原因:每一次轮回过后,未排序的值最大元素都会被“冒泡”到最右边。以上的7步操作只是第一轮,还要经过4轮,数组才会被排序好为[1,2,3,4,7]

冒泡排序算法代码实现

        //冒泡排序算法
        int[] numbers=new int[]{4,2,7,1,3};
        for(int i=0;i<numbers.length-1;i++)
        {
            for(int j=0;j<numbers.length-1-i;j++)
            {
                if(numbers[j]>numbers[j+1])
                {
                    int temp=numbers[j];
                    numbers[j]=numbers[j+1];
                    numbers[j+1]=temp;
                }
            }
        }

冒泡排序效率

冒泡排序的执行步骤分为两步:1.比较 2.交货顺序

经过四轮比较:4+3+2+1=10,若为N个元素,需要 (N-1)+(N-2)+...+1次比较; 经过最坏的情况,每次比较都要排序,也是(N-1)+(N-2)+...+1次比较,所以总共步数是N²-N,记为O(N²)

选择排序

选择排序举例说明

假设要对[4,2,7,1,3]进行排序

  • 第一步:将索引0和索引1的值比较,即4和2的值,4比2大,最小值为2
  • 第二步:7与2比较,最小值为2
  • 第三步:1与2比较,更新最小值为1
  • 第四步:3与1比较,最小值为1
  • 第五步:将1与4进行交换,顺序为[1,2,7,4,3]

经过5步操作之后,我们把最小的元素[1],换到了最左边,还要经过4轮,数组才会被排序好为[1,2,3,4,7]

选择排序算法代码实现

        //选择排序算法
        int[] arr=new int[]{4,2,7,1,3};
        for(int i = 0; i < arr.length - 1; i++) {// 做第i趟排序
            int k = i;
            for(int j = k + 1; j < arr.length; j++){// 选最小的记录
                if(arr[j] < arr[k]){
                    k = j; //记下目前找到的最小值所在的位置
                }
            }
            //在内层循环结束,也就是找到本轮循环的最小的数以后,再进行交换
            if(i != k){  //交换a[i]和a[k]
                int temp = arr[i];
                arr[i] = arr[k];
                arr[k] = temp;
            }
        }

选择排序效率

选择排序的执行步骤分为两步:1.比较 2.交货顺序,但是与冒泡排序不同的是,在最坏的情况下,每轮的交换最多只有一次,若元素为N个,则需要需要 (N-1)+(N-2)+...+1次比较,总共步数为N²/2+N-1,记为O(N²/2)

插入排序

插入排序举例说明

假设要对[4,2,7,1,3]进行排序

  • 第一轮准备工作:将索引1的值[2]移走,并将值存在临时变量tempValue中;
  • 第一步:4与tenmpValue[2]比较,4大于2
  • 第二步:将4右移
  • 第三步:将tempValue值,插回数组,顺序为[2,4,7,1,3],结束第一轮
  • 第二轮准备工作:将索引2的值[7]移走,并将值存在临时变量tempValue中;
  • 第四步:4与tenmpValue[7]比较,4小于7无需平移
  • 第五步:将tempValue值插回原有空隙,顺序为[2,4,7,1,3],结束第二轮
  • 第三轮准备工作:将索引3的值[1]移走,并将值存在临时变量tempValue中;
  • 第六步:7与tenmpValue[1]比较
  • 第七步:7比1大,往右平移一位
  • 第八步:4与tenmpValue[1]比较
  • 第九步:4比1大,往右平移一位
  • 第十步:2与tenmpValue[1]比较
  • 第十一步:2比1大,往右平移一位
  • 第十二步:到了数组最左端,无值比较,将tempValue插入,结束第三轮,顺序为[1,2,4,7,3]
  • 第四轮准备工作:将索引4的值[3]移走,并将值存在临时变量tempValue中;
  • 第十三步:7与tenmpValue[3]比较
  • 第十四步:7比3大,往右平移一位
  • 第十五步:4与tenmpValue[3]比较
  • 第十六步:4比3大,往右平移一位
  • 第十七步:2与tenmpValue[3]比较
  • 第十八步:2比tenmpValue[3]小,插回空隙,顺序为[1,2,3,4,7]

插入排序算法代码实现

        //插入排序算法
        for(int index = 1; index<length; index++){//外层向右的index,即作为比较对象的数据的index
            int temp = array[index];//用作比较的数据
            int leftindex = index-1;
            while(leftindex>=0 && array[leftindex]>temp){//当比到最左边或者遇到比temp小的数据时,结束循环
                array[leftindex+1] = array[leftindex];
                leftindex--;
            }
            array[leftindex+1] = temp;//把temp放到空位上
        }

插入排序效率

插入排序分为4中步骤:1.移除 2.比较 3.平移 4.插入 在最坏的情况下,平移和比较的次数一样,为: (N-1)+(N-2)+...+1,即N²-N/2;插入和移除的次数一样,都为N-1.所以总共的次数为N²+N-2,记为O(N²)

冒泡排序、选择排序、插入排序比较

排序算法 总共步数 O计数
冒泡排序 N²-N O(N²)
选择排序 N²/2+N-1 O(N²/2)
插入排序序 N²+N-2 O(N²)

以上我们讨论的是最坏情况,但是在现实生活中,我们考虑的是平均情况,具体情况使用算法,如果能够确信数组是大致有序的,则用插入排序会更好些,大致逆序,则用选择排序。如果不能确定的话,则两种都可以

快速排序

快速排序依赖于分区算法,步骤如下:

  1. 左指针逐个向右移动,当遇到大于或等于轴的值时,停下来
  2. 右指针逐个向、左移动,当遇到小于或等于轴的值时,停下来
  3. 将两针所指的值交换位置
  4. 重复以上步骤,直致两指针重合
  5. 将轴与左指针的值交换位置

快速排序举例说明

假设要对[4,2,7,1,3]进行排序

  • 准备工作3为轴,左指针为4,1为右指针
  • 第一步:左指针[4]比轴[3]大,不动
  • 第二步:右指针[1]比轴[3]小,不动
  • 第三步:左右指针停止,交换位置,顺序为[1,2,7,4,3],3为轴,左指针为1,右指针为4
  • 第四步:左指针[1]比轴[3]小
  • 第五步:右移左指针,左指针为[2]
  • 第六步:左指针[2]比轴[3]小
  • 第七步:右移左指针,左指针为[7]
  • 第八步:左指针[7]比轴[3]大,不动
  • 第九步:右指针[4]比轴[3]大,右指针左移
  • 第十步:两个指针指向同一个值[7],交换左指针[7]和轴[3]的位置,顺序为[1,2,3,4,7]

快速排序算法代码实现

    //快速排序算法
    private static void quickSort(Integer[] arr, int low, int high) {
        if(low < high){
            int part=partition(arr,low,high);
            //递归调用
            quickSort(arr,low,part-1);
            quickSort(arr,part+1,high);
        }
    }
    //分区算法实现
    private static int partition(Integer[] arr, int low, int high) {
        //使用 r[low]作为枢轴元素
        int pivot = arr[low];
        //从两端交替向内扫描
        while(low < high){
            while(low<high && arr[high] >= pivot) {high--;}
            //将比 pivot 小的元素移向低端
            arr[low] = arr[high];
            while(low<high && arr[low] <= pivot){low++;}
            //将比 pivot 大的元素移向高端
            arr[high] = arr[low];
        }
        //设置枢轴
        arr[low]=pivot;
        //返回枢轴元素位置
        return low;
    }

快速排序效率

排序算法 最好情况 平均情况 最坏情况
插入排序 O(N) O(N²) O(N²)
快速排序 O(N㏒N) O(N㏒N) O(N²)