经典排序算法

一.算法的分类

相关概念:

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

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

时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。

空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

二.冒泡排序(BubbleSort)

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 

核心思想:相邻逆序就交换

1.1 算法描述

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

1.2 动图演示

1.3 代码实现

import java.util.Scanner;

public class BubbleSort {
    public static void main(String[] args) {
        //int a[] = {12,1,3,4,7,2,5};
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一维数组,数组长度为10:");
        int[] a = new int[10];
        for(int i = 0;i < 10;i++){
            a[i] = scanner.nextInt();
        }
        bubbleSort(a);
        System.out.println("冒泡排序后的顺序:");
        for(int i=0;i<a.length;i++){
                if(a[i]!=a[a.length-1])
                    System.out.print(a[i]+",");
                else
                    System.out.println(a[i]);
        }
    }

    private static void bubbleSort(int[] a) {
        //外层循环记录冒泡的趟数,总共进行a.length-1趟排序
        for(int i=0;i<a.length-1;i++){
            //内层循环记录一趟循环比较的次数
            for(int j=0;j<a.length-i-1;j++){
                if(a[j]>a[j+1]){
                    int temp = a[j+1];
                    a[j+1] = a[j];
                    a[j] = temp;
                }
            }
        }
    }
}

       N个元素需要排序N-1轮;

  第i轮需要比较N-i次;

  N个元素排序,需要比较n(n-1)/2次;

  冒泡排序的算法复杂度较高,为O(n*n)

三.快速排序(Quick Sort)

改进冒泡排序中一次只能消除一个逆序的缺点,即实现一次交换消除多个逆序

快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

package com.luo.sort;

public class QuickSort {
    public static void main(String[] args) {
        int arr[] = {3,5,1,4,7,9,8};
        int start = 0;
        int end = arr.length - 1;
       quickSort(arr,start,end);
        for (int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }

    private static void quickSort(int[] arr,int lo,int hi) {
        int left = lo;
        int right = hi;

        if(left>=right){
            return;
        }

        int key = arr[left] ;

        while (left<right){
            //1.先从后往前扫描,找比key小的
            while (arr[right]>=key && right>left){
                right--;
            }
            //找到之后,替换掉基准位的值
            if(left<right){
                arr[left] = arr[right];
                left++;
            }

            //2.从前往后找,找比key大的
            while (arr[left]<=key && right>left){
                left++;
            }
            //找到之后,填补右侧之前替换掉的基准位的值的位置空缺
            if(left<right){
                arr[right] = arr[left];
                right--;
            }
        }

        arr[right] = key;

        quickSort(arr,lo,left-1);//比基准数小的再排序(左边)
        quickSort(arr,right+1,hi);//比基准数大的再排序(右边)
    }

}

 四.选择排序

 选择排序是对冒泡排序的改进,它的比较次数与冒泡排序相同,但交换次数要小于冒泡排序。当数据量较大时,效率会有很大的提升,但时间复杂度仍为O(n*n)

原理:

       1、从第一个元素开始,分别与后面的元素向比较,找到最小的元素与第一个元素交换位置;

  2、从第二个元素开始,分别与后面的元素相比较,找到剩余元素中最小的元素,与第二个元素交换;

  3、重复上述步骤,直到所有的元素都排成由小到大为止。

待比较数据:7, 6, 9, 8, 5,1

  第一轮:此时指针指向第一个元素7,找出所有数据中最小的元素,即1,交换7和1的位置,排序后的数据为:1,6,9,8,5,7

  第二轮:第一个元素已经为最小的元素,此时指针指向第二个元素6,找到6,9,8,5,7中最小的元素,即5,交换5和6的位置,排序后的结果为:1,5,9,8,6,7

  第三轮:前两个元素为排好序的元素,此时指针指向第三个元素9,找到9,8,6,7中最小的元素,即6,交换6和9的位置,排序后的结果为:1,5,6,8,9,7

  第四轮:前三个元素为排好序的元素,此时指针指向第四个元素8,找到8,9,7中最小的元素,即7,交换8和7的位置,排序后的结果为:1,5,6,7,9,8

  第五轮:前四个元素为排好序的元素,此时指针指向第五个元素9,找到9,8中最小的元素,即8,交换9和8的位置,排序后的结果为:1,5,6,7,8,9

  到此,全部排序完成。

package com.luo.sort;

public class SelectSort {
    public static void main(String[] args) {
        int[] arr =  {6,1,2,7,9,3,4,5,10,8};
        selectSort(arr);
        for (int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }

    private static void selectSort(int[] arr) {
        for(int i=0;i<arr.length-1;i++){
            for(int j=i+1;j<arr.length;j++){
                if(arr[i]>arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
//    private static void selectSort(int[] arr) {
//
//
//        //外层循环记录排序的t趟数,和冒泡排序类似,N个元素进行N-1趟排序
//        for(int i=0;i<arr.length-1;i++){
//            //将i指向最小元素的下标
//            int minIndex = i;
//            for (int j=i+1;j<arr.length;j++){
//                if(arr[j]<arr[minIndex]){
//                    minIndex = j;
//                }
//            }
//            int temp = arr[i];
//            arr[i] = arr[minIndex];
//            arr[minIndex] = temp;
//
//
//        }
//    }

}

      N个元素需要排序N-1轮;

  第i轮需要比较N-i次;

  N个元素排序,需要比较n(n-1)/2次;

  选择排序的算法复杂度仍为O(n*n);

  相比于冒泡排序,选择排序的交换次数大大减少,因此速度要快于冒泡排序

五.插入排序

插入排序是简单排序中最快的排序算法,虽然时间复杂度仍然为O(n*n),但是却比冒泡排序和选择排序快很多。

原理:插入排序算法有种递归的思想在里面,它由N-1趟排序组成。初始时,只考虑数组下标0处的元素,只有一个元素,显然是有序的。

然后

第一趟 对下标 1 处的元素进行排序,保证数组[0,1]上的元素有序;

第二趟 对下标 2 处的元素进行排序,保证数组[0,2]上的元素有序;
.....
.....
第N-1趟对下标 N-1 处的元素进行排序,保证数组[0,N-1]上的元素有序,也就是整个数组有序了。

它的递归思想就体现在:当对位置 i 处的元素进行排序时,[0,i-1]上的元素一定是已经有序的了。

待比较数据:7, 6, 9, 8, 5,1

  第一轮:指针指向第二个元素6,假设6左面的元素为有序的,将6抽离出来,形成7,_,9,8,5,1,从7开始,6和7比较,发现7>6。将7右移,形成_,7,9,8,5,1,6插入到7前面的空位,结果:6,7,9,8,5,1

  第二轮:指针指向第三个元素9,此时其左面的元素6,7为有序的,将9抽离出来,形成6,7,_,8,5,1,从7开始,依次与9比较,发现9左侧的元素都比9小,于是无需移动,把9放到空位中,结果仍为:6,7,9,8,5,1

  第三轮:指针指向第四个元素8,此时其左面的元素6,7,9为有序的,将8抽离出来,形成6,7,9,_,5,1,从9开始,依次与8比较,发现8<9,将9向后移,形成6,7,_,9,5,1,8插入到空位中,结果为:6,7,8,9,5,1

  第四轮:指针指向第五个元素5,此时其左面的元素6,7,8,9为有序的,将5抽离出来,形成6,7,8,9,_,1,从9开始依次与5比较,发现5比其左侧所有元素都小,5左侧元素全部向右移动,形成_,6,7,8,9,1,将5放入空位,结果5,6,7,8,9,1。

  第五轮:同上,1被移到最左面,最后结果:1,5,6,7,8,9。

package com.luo.sort;

public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {6,1,2,7,9,3,4,5,10,8};
        insertSort(arr);
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+" ");
        }
    }

    private static void insertSort(int[] arr) {
        //外层记录排序的趟数,总共进行n-1趟(第1个元素到最后一个元素)比较
        for(int i=0;i<arr.length;i++){
            //内层循环记录比较元素的次数,假设左边的元素是有序的,开始时arr[0]有序,第二次选中arr[1],然后对选中的元素分别从
            // 选中的位置开始向左进行比较,若小于前一个,则交换位置,
            for(int j=i; (j>0)&&(arr[j]<arr[j-1]); j--){
                swap(arr,j,j-1);
            }
        }
    }

    private static void swap(int[] arr, int j, int i) {
        int temp = arr[j];
        arr[j] = arr[i];
        arr[i] = temp;
    }
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值