JAVA数据结构 08.排序算法(1) 排序算法的介绍和分类 算法的时间复杂度 冒泡排序 选择排序 插入排序 希尔排序

JAVA数据结构 08.排序算法(1)

1.排序算法的介绍和分类

排序:将一组数据,以指定的顺序进行排列的过程

排序的分类:

  • 内部排序:将需要的所有数据加载到内存中进行排序**(8大排序算法)**
    • 插入排序
      • 直接插入排序
      • 希尔排序
    • 选择排序
      • 简单选择排序
      • 堆排序
    • 交换排序
      • 冒泡排序
      • 快速排序
    • 归并排序
    • 基数排序
  • 外部排序:数据量过大,无法全部加载到内存中,需要借助外存进行排序,先部分排序后合并

度量一个排序算法:

  • 算法的时间复杂度

在这里插入图片描述
在这里插入图片描述

  • 算法的空间复杂度

2. 八大排序算法 实现 解析 和优化

2.1 冒泡排序

基本思想:通过对待排序序列从前向后,依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后面.

简单方法(待优化):不考虑其他条件,直接对数组内所有元素进行两层for循环实现

public static void stupid(int arr[]){
    
    
    for (int i = 0; i <arr.length ; i++) {
    
    
        for (int j = 0; j <arr.length -1 ; j++) {
    
    
            if(arr[j]>arr[j+1]){
    
    
                //swap
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

算法图解:

在这里插入图片描述

冒泡规律小结: 使用规律来优化

  • 对所有元素的排序只需要进行数组长度-1
  • 每一轮的排序,元素比较和交换的次数减少
  • 因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较

算法优化:

public static void smart(int arr[]){
    
    
    for (int i = 0; i <arr.length -1 ; i++) {
    
      //优化1:一共进行数组的大小-1次大的循环
        boolean flag = true;        //优化3:设置一个表示flag判断元素是否进行交换,从而减少不必要的比较
        for (int j = 0; j <arr.length -1 - i ; j++) {
    
      //优化2:每一趟排序的次数在逐渐的减少i
            if(arr[j]>arr[j+1]){
    
    
                //swap
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
                flag = false;
            }
        }
        if(flag) break;
    }
}

2.2 选择排序

算法思路:从欲排序的数据中,按指定的规则选出某一元素,再依次规定交换位置后达到排序的目的.

  • 以从小到大排序为例,将n个待排序的元素看称一个有序表一个无序表
  • 每一轮从无序表元素中找到最小的数字,与无序表的第一个元素进行交换.(无序表场地-1,有序表长度+1)
  • 总共通过n-1次,得到一个有序序列

算法图解:

在这里插入图片描述

  • 选择排序进行数组大小-1轮排序
  • 每一轮的排序,又是一个循环,找到剩下待排序数中最小的数执行交换,与冒泡相比减少了交换次数

算法实现和优化:

public static void selectSort(int arr[]){
    
    
    for (int i = 0; i <arr.length - 1 ; i++) {
    
    
        int index = i;
        for (int j = i+1 ; j <arr.length ; j++) {
    
       //优化1. j从i+1开始进行比较,减少依次 j和i的对比(自我比较)
            //找arr[j]~arr[length]中最小的数的下标
            if(arr[index]>arr[j]){
    
    
                index = j;
            }
        }
        if(index != i){
    
     //优化2.当最小值是arr[i]本身时 无需交换
            //交换最小数和i的位置
            int temp = arr[index];
            arr[index] = arr[i];
            arr[i] = temp;
        }
    }
}

2.3 插入排序

算法思路:对欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的.

  • 将n个待排序的元素看称一个有序表一个无序表
  • 开始时有序表中只包含一个元素,无序表中包含n-1个元素
  • 排序过程中每次从无序表中取出第一个元素,将它依次与有序表进行比较
  • 找到合适顺序位置后插入操作(数组的插入需要整体移动)

算法图解:

在这里插入图片描述

算法实现:

public static void inserSort(int arr[]){
    
    
    for (int i = 1; i <arr.length ; i++) {
    
    
        //待插入的数字
        int insertVal = arr[i];
        //已经排好序的数组中最大的一个元素
        int insertIndex = i-1;
        //判断:待排序数是否大于插入位置,找到插入点
        while (insertIndex >=0 && insertVal < arr[insertIndex]){
    
    
            //后移arr[insertIndex]
            arr[insertIndex+1] = arr[insertIndex];
            insertIndex --; //判断有序表前一个元素
        }
        //循环结束以后,已经找到待插入的位置为insertIndex+1
        arr[insertIndex +1 ] = insertVal;
    }
}

插入排序存在的明显问题:当需要插入较小的数时,需要将多位有序表中的数进行后移,后移次数增多,对效率影响大(优化方法:希尔排序)

2.4 希尔排序

算法介绍:希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效版本,也称为缩小增量排序

算法思想:

  • 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;
  • 随着随着增量逐渐减少,每组包含的元素越来越多,当增量减到1时,整个数组恰被分成一组,算法终止

算法图解:

在这里插入图片描述

代码实现:

交换式希尔排序实现: 这是对冒泡排序的升级,先进行分组冒泡,再进行合并冒泡,减少元素之间的交换次数,但需要多轮冒泡,速度很慢

public static void sheelSortSwap(int arr[]){
    
    
    int count = 0;
    int temp = 0;
    for(int gap = arr.length/2;gap>0;gap /=2){
    
    
        //分组内可用理解为一个冒泡排序,每次将组内最小的数换到第一个,实现组内有序
        for (int i = gap; i <arr.length ; i++) {
    
    
            for (int j = i-gap; j >=0 ; j-=gap) {
    
    
                if(arr[j]>arr[j+gap]){
    
    
                    temp = arr[j];
                    arr[j] = arr[j+gap];
                    arr[j+gap] = temp;
                    count ++;
                }
            }
        }
    }

    System.out.println(count);
}

移动式希尔排序:这是对插入排序的升级,先进行分组插入,再进行合并插入,减少元素之间的移动

    public static void sheelSortMove(int arr[]) {
    
    
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
            //从gap个元素开始,逐个对其所在的组进行直接插入排序
            //元素间隔为gap的插入排序
            for (int i = gap; i < arr.length; i++) {
    
    
                int insertIndex = i;
                int insertValue = arr[insertIndex];
                while (insertIndex - gap >= 0 && insertValue < arr[insertIndex - gap]) {
    
    
                    arr[insertIndex] = arr[insertIndex - gap];
                    insertIndex -= gap;
                }
                //此时找到了temp的位置
                arr[insertIndex] = insertValue;
            }
        }
    }
rr[insertIndex] = arr[insertIndex - gap];
                    insertIndex -= gap;
                }
                //此时找到了temp的位置
                arr[insertIndex] = insertValue;
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/weixin_44634197/article/details/108684418