数据结构与算法 09 排序算法 时间复杂度 冒泡排序 希尔排序 插入排序 选择排序

排序算法

分类

  1. 内部排序:将需要处理的数据加载到内存中进行排序;
  • 插入排序:直接插入排序 希尔排序
  • 选择排序:简单选择排序 堆排序
  • 交换排序:冒泡排序 快速排序
  • 归并排序
  • 基数排序 - 桶排序升级版
  1. 外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序(内存与外存结合)

算法的时间复杂度

  1. 事后统计:程序运行的时间;需要运行程序、依赖于计算机的硬件、软件等环境因素
  2. 事前估算的方法:分析算法的时间复杂度

时间频度

时间频度:一个算法花费的时间与算法的执行次数成正比例,一个算法中语句执行次数称为语句频度或时间频度,T(n)

// case 1
int total = 0;
int end = 100;
for(int i = 1; i <= end; i++){
     
  total += i;
}
// T(n) = n + 1 总共执行了 n+1 次

// case 2
total = (1 + end)* end / 2;
// T(n) = 1

忽略常数项

忽略低次项

忽略系数


时间复杂度

O(n) : time complexity,一般讨论最坏时间复杂度

不考虑常数,只保留最高阶,不考虑系数

常数阶 O(1):没有循环等复杂结构,消耗的时间不随某个变量的增长而增长

对数阶 O(log2n):while循环

线性阶 O(n):单层for循环

线性对数阶 O(nlog2n):将线性阶的代码循环n遍

平方阶 O(n^2):双层for循环

立方阶 O(n^3)

k次方阶 O(n^k)

指数阶 O(2^n)


空间复杂度

占用存储空间大小的量度 space complexity


冒泡排序

依次比较相邻元素的值,如果发现逆序,则交换,使值较大的元素从前向后移

优化:如果一轮比较下来没有进行交换,说明序列有序,因此在排序过程中设置一个flag判断元素是否进行锅交换

注意:以下代码是按照升序排序,因此第一轮排序之后最大值确定,下一轮排序的范围为 0-arr.length-1-i

时间复杂度:O(n^2)

package sort;

public class BubbleSort {
     
    public static void main(String[] args) {
     
        int[] arr = {
     1,34,2,4,56,23,7};
        int[] arr2 = bubble(arr);
        for (int i = 0; i < arr2.length; i++) {
     
            System.out.print(arr[i]+"\t");
        }
    }

    private static int[] bubble(int[] arr) {
     
        int temp = 0;
        for (int i = 0; i < arr.length-1; i++) {
     
            boolean flag = false;
            for (int j = 0; j < arr.length-1-i; j++) {
     
                if(arr[j]>arr[j+1]){
     
                    temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                    flag = true;
                }
            }
            if(flag == false){
     
                break;
            }else{
     
              flag = true; // reset flag for next loop
            }
        }
        return arr;
    }
}

测试时间

package sort;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class BubbleSortTest {
     
    public static void main(String[] args) {
     
        int[] arr = new int[80000];
        for (int i = 0; i < 80000; i++) {
     
            arr[i] = (int)(Math.random()*8000000); // [0,8000000)
        }
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str = format.format(date);
        System.out.println("before sorting "+ date1Str);

        bubble(arr);

        Date date2 = new Date();
        String date2Str = format.format(date2);
        System.out.println("after sorting "+ date2Str);


    }
    private static void bubble(int[] arr) {
     
        int temp = 0;
        for (int i = 0; i < arr.length-1; i++) {
     
            boolean flag = false;
            for (int j = 0; j < arr.length-1-i; j++) {
     
                if(arr[j]>arr[j+1]){
     
                    temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                    flag = true;
                }
            }
            if(flag == false){
     
                break;
            }else{
     
                flag = false; // reset flag for next loop
            }
        }
    }
}

结果:

before sorting 2020-06-14 10:09:58
after sorting 2020-06-14 10:10:09

选择排序

selection sort

时间复杂度:O(n^2) 时间会缩短很多

基本思想:第一次从整个数组中找到最小值和 arr[0] 进行交换;第二次从 arr[1] - arr[n-1] 中找到最小值和 arr[1] 交换,第三次从 arr[2] - arr[n-1] 找到最小值和 arr[2] 进行交换…第 n-1 次从 arr[n-2] - arr[n-1] 中选取最小值和 arr[n-2] 交换,总共 n-1 次得到一个从小到大的序列

  1. 选择排序一共有数组大小 -1 轮排序
  2. 每一轮排序,又是一个循环
  3. 先假定当前的这个数是最小数
  4. 然后和后面的每个数进行比较,如果发现有比当前数更小的数,就重新确定最小数,并获取下标
  5. 当遍历到数组的最后时,就得到本轮最小数和下标
  6. 进行交换

代码

引入 minIndex 获取最小值的下标

package sort;

import java.util.Arrays;

public class SelectionSort {
     
    public static void main(String[] args) {
     
        //int[] arr = {1,34,2,4,56,23,7,-1,20};
        //System.out.println(Arrays.toString(arr));
        //select(arr);
        //System.out.println(Arrays.toString(arr));
      	int[] arr = new int[80000];
        for (int i = 0; i < 80000; i++) {
     
            arr[i] = (int)(Math.random()*8000000); // [0,8000000)
        }
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str = format.format(date);
        System.out.println("before sorting "+ date1Str);

        select(arr);

        Date date2 = new Date();
        String date2Str = format.format(date2);
        System.out.println("after sorting "+ date2Str);
    }

    private static void select(int[] arr) {
     
        for (int i = 0; i < arr.length-1; i++) {
     
            int minIndex = i;
            int min = arr[i];
            for (int j = i+1; j < arr.length; j++) {
     
                if(min>arr[j]){
     
                    min = arr[j];
                    minIndex = j;
                }
            }
            if(minIndex!=i){
     
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
        }
    }
}
before sorting 2020-06-14 10:47:26
after sorting 2020-06-14 10:47:29

插入排序

insertion sort 时间复杂度:O(n^2)

基本思想: 将n个待排序的元素看成一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有 n-1 个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表


将待插入的数据保存的变量中,定义插入的下标

  1. insertIndex>=0 保证在给 insertVal 找插入位置时不会越界
  2. insertVal < arr[insertIndex] 待插入的数,还没有找到插入位置
  3. 需要将 arr[insertIndex] 后移
  4. 当退出 while 循环时,说明找到了插入的位置 arr[insertIndex]+1
package sort;

import java.util.Arrays;

public class InsertionSort {
     
    public static void main(String[] args) {
     
        int[] arr = {
     1,34,2,4,56,23,7,-1,20};
        System.out.println(Arrays.toString(arr));
        insert(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void insert(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 + 1] = arr[insertIndex]; // 后移
                insertIndex--;
            }
          	if(insertIndex+1!=i){
     
              arr[insertIndex + 1] = insertVal;
            }
        }
    }
}
TEST TIME:
before sorting 2020-06-14 14:31:21
after sorting 2020-06-14 14:31:22

希尔排序

shell sorting 也是一种插入排序;也称为缩小增量排序

基本思想:把记录按照下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰好分成一组,算法结束


对有序序列在插入时有两种方法:交换法;移动法


交换法

package sort;

import java.util.Arrays;

public class ShellSortExchange {
     
    public static void main(String[] args) {
     
        int[] arr = {
     1,34,2,4,56,23,7,-1,20};
        System.out.println(Arrays.toString(arr));
        shell(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void shell(int[] arr) {
     
        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 current value is greater than the value added 5 steps
                    // exchange them
                    if(arr[j]>arr[j+gap]){
     
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
        }
    }
}
time:
before sorting 2020-06-14 15:10:09
after sorting 2020-06-14 15:10:15

移位法

package sort;

import java.util.Arrays;

public class ShellSortMove {
     
    public static void main(String[] args) {
     
        int[] arr = {
     1,34,2,4,56,23,7,-1,20};
        System.out.println(Arrays.toString(arr));
        shell(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void shell(int[] arr) {
     
        for(int gap = arr.length / 2; gap > 0; gap /= 2){
     
            for(int i = gap; i < arr.length; i++){
     
                int j = i;
                int temp = arr[j]; // 待插入的数
                if(arr[j]<arr[j-gap]){
     
                    while(j-gap>=0 && temp<arr[j-gap]){
     
                        // move
                        arr[j] = arr[j-gap];
                        j -= gap;
                    }
                    // when quit while loop, found location for inserting temp
                    arr[j] = temp;
                }
            }
        }
    }
}
time:
before sorting 2020-06-14 15:29:08
after sorting 2020-06-14 15:29:08

你可能感兴趣的:(数据结构与算法java,算法,数据结构,排序算法,java,插入排序)