数据结构与算法从零开始系列:冒泡排序、选择排序、插入排序

本篇内容包含

  • 排序的介绍
  • 排序的C的实现
  • 排序的Java的实现
  • 排序的时间复杂度的计算

(一)冒泡排序

1、基本思想:

两个数比较大小,较大的数下沉,较小的数冒起来

2、实现步骤:

这张图就是将数字12,35,99,18,76竖起来

  • 第一次:从底部有一个气泡,圈住12并且和35对比,如果比上面小就交换,气泡往上升
  • 第二次:12和99对比,如果比上面小就交换,气泡往上升
  • 第三次:重复上面的操作,最后可以把12排到最上面

3、这张图模拟了冒泡排序的整个过程

  • 第一个红色框表示气泡
  • 两个红色框表示比较大小
  • 黑色框表示已经排好的数字
  • 最后排成有序的数字

冒泡排序的C的实现

1、程序优化:

  • 这里加了一个flag作为优化程序的条件,如果程序未进入内循环,说明数字已经排序好了,后面的比较也就没有意义了,直接程序结束

2、实现口诀:

  • 两数相抱转个圈

3、易犯错误:

  • 忘记添加优化flag
#include<stdio.h>

void bubbleSort(int arr[],int n){
    int i,j,flag;
    for (i = 1; i < n; i++) {
        flag = 0;
        for (j = 0; j < n-i; j++) {
            if(arr[j]<arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
                flag =1;
            }
        }
        if(flag == 0)break;
    }
}

void main(){
    int i;
    int arr[10] = {1, 4, 8, 3, 2, 9, 5, 0, 7, 6};
    bubbleSort(arr, 10);

    //9,8,7,6,5,4,3,2,1,0,
    for(i=0; i<10; i++){
        printf("%d,", arr[i]);
    }
}

冒泡排序的Java的实现

public class BubbleSort {

    public void bubbleSort(int[] arr,int n){
        boolean flag;
        for (int i = 1; i < n; i++) {
            flag = false;
            for (int j = 0; j < n-i; j++) {
                if(arr[j]<arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag =true;
                }
            }
            if(!flag)break;
        }
    }

    public static void main(String[] args) {
        int[] arr = {1, 4, 8, 3, 2, 9, 5, 0, 7, 6};
        BubbleSort sort = new BubbleSort();
        sort.bubbleSort(arr, arr.length);

        //9,8,7,6,5,4,3,2,1,0,
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+",");
        }
    }
}

冒泡排序的时间复杂度的计算

1、我们从代码分析,可以知道有两个循环

  1. 外循环:执行(n-1)次,当最坏的情况下,会执行n次,虽然最后一次(i < n)不通过,但还是算一次,其中里面有一条赋值语句
  2. 内循环:在(i=1,2,3…n-1),执行(n-i)次,即(n-1,n-2…1),其中有四条赋值语句

2、那么就可以计算出各自复杂度

  1. 外循环:最坏情况下是(1 x n)次
  2. 内循环:通过等差数列求和公式,(n-1+n-2+…1)=n^2/2

3、根据推导大O阶规则来进行推导

  1. 用常数1来取代运行时间中所有加法常数
  2. 修改后的运行次数函数中,只保留最高阶项
  3. 如果最高阶项存在且不是1,则去除与这个项相乘的常数

4、得到的冒泡排序的复杂度的大O表示法为

(1xn)+(n^2/2) ≈ n^2 = O(n^2)

(二)选择排序

1、基本思想:

  • 让第一个数与后面的所有数一个个比较,找出最小的数,将最小的数跟第一个数交换
  • 接着从第二个数开始,继续上面的操作

2、实现步骤:

选择排序的C的实现

1、注意点:

  • 用语言实现排序的时候,只是记录着最小值的下标,接着用最小值的下标继续和后面的数进行比较,这是和思路不同的地方

2、实现口诀:

  • 角标互换

3、易犯错误:

  • 忘记添加角标判断
#include<stdio.h>

void selectSort(int arr[],int n){
    int i,j,minIndex;
    for (i = 0; i < n-1; i++) {
        minIndex = i;
        for (j = i+1; j < n; j++) {
            if(arr[j]<arr[minIndex]){
                minIndex = j;
            }
        }
        if(minIndex!=i){
            int temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}
void main(){
    int i;
    int arr[8] = {3, 1, 5, 7, 2, 4, 9, 6};
    selectSort(arr, 8);

    //1,2,3,4,5,6,7,9,
    for(i=0; i<8; i++){
        printf("%d,", arr[i]);
    }
}

选择排序的Java的实现

public class SelectSort {

    public void selectSort(int arr[], int n) {
        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                int temp = arr[minIndex];
                arr[minIndex] = arr[i];
                arr[i] = temp;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {3, 1, 5, 7, 2, 4, 9, 6};
        SelectSort sort = new SelectSort();
        sort.selectSort(arr, arr.length);

        //1,2,3,4,5,6,7,9,
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ",");
        }
    }
}

选择排序的时间复杂度的计算

1、我们从代码分析,可以知道有两个循环

  1. 外循环:执行(n-1)次,当最坏的情况下,会执行n次,虽然最后一次(i < n)不通过,但还是算一次,其中里面有四条赋值语句
  2. 内循环:在(j=1,2,3…n-1),执行(n-i)次,即(n-1,n-2…1),其中有一条赋值语句

2、那么就可以计算出各自复杂度

  1. 外循环:最坏情况下是(4 x n)次
  2. 内循环:通过等差数列求和公式,(n-1+n-2+…1)=n^2/2

3、复杂度的大O表示法为

(4xn)+(1x(n^2/2)) ≈ n^2 = O(n^2)

(三)插入排序

1、基本思想:

  • 其实就是你玩扑克牌的时候,排序你自己的牌的思路
  • 从后面抽出牌,插入到前面的牌中

2、实现步骤:

  • 初始值:1, 4, 8, 3, 2, 9, 5, 0, 7, 6
  • 第一次:抽出牌4,与1对比,发现比它大,不交换
  • 第二次:抽出牌8,与4对比,发现比它大,不交换
  • 第三次:抽出牌3,与8对比,发现比它小,交换,继续与前面一个数比,与4对比,发现比它小,交换,继续与前面一个数比,与1对比,发现比它大,不交换
  • 第四次:重复上面步骤,完成扑克牌排序

插入排序的C的实现

1、实现口诀:

  • 扑克牌往回插

2、易犯错误:

  • 忘记退出的break
#include<stdio.h>

void insertSort(int arr[],int n){
    int i,j;
    for (i = 0; i < n - 1; i++) {
        for (j = i + 1; j > 0; j--) {
            if (arr[j] < arr[j - 1]) {
                int temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
            } else {
                break;
            }
        }
    }
}

void main(){
    int i;
    int arr[10] = {1, 4, 8, 3, 2, 9, 5, 0, 7, 6};
    insertSort(arr, 10);

    //0,1,2,3,4,5,6,7,8,9,
    for(i=0; i<10; i++){
        printf("%d,", arr[i]);
    }
}

插入排序的Java的实现

public class InsertSort {

    public void insertSort(int[] arr, int n) {
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j > 0; j--) {
                if (arr[j] < arr[j - 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                } else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {1, 4, 8, 3, 2, 9, 5, 0, 7, 6};
        InsertSort sort = new InsertSort();
        sort.insertSort(arr, arr.length);

        //0,1,2,3,4,5,6,7,8,9,
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ",");
        }
    }
}

插入排序的时间复杂度的计算

1、我们从代码分析,可以知道有两个循环

  1. 外循环:执行(n-1)次,当最坏的情况下,会执行n次,虽然最后一次(i < n)不通过,但还是算一次
  2. 内循环:在(i=0,1,2,3…n-2),执行(n-i-1)次,即(n-1,n-2…1),其中有三条赋值语句

2、那么就可以计算出各自复杂度

  1. 外循环:最坏情况下是(n)次
  2. 内循环:通过等差数列求和公式,3x(n-1+n-2+…1)=(3x(n^2/2))

3、复杂度的大O表示法为

(n)+(3x(n^2/2)) ≈ n^2 = O(n^2)

你可能感兴趣的:(java,数据结构,算法,C语言)