面试题一天一题——第八天 · (手写冒泡排序及优化)

数据结构和算法是一个积累的过程,如果平时没有刷刷题或者养成做算法的习惯;在面试的时候还是不太建议去做算法方面的题目,当然这只是我个人的想法;在这段时间做题的时候,总是遇到一些面经上有一到两道算法题目,所以在这里记录一下简单的算法题!

冒泡排序原理

百度百科:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。


    面试题一天一题——第八天 · (手写冒泡排序及优化)_第1张图片
    冒泡排序.gif


1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

首先,我们实现第一步,比较相邻的两个元素,如果第一个比第二个要大,则将他们进行交换。当从开始到结束之后,第一轮循环结束,此时最大的数将到达数组的最后一个位置。

public class BubbleSort {
    @Test
    public void testBubbleSort() {
        int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
        for(int i: arr) {
            System.out.print(i + " ");
        }
        bubbleSort(arr);
        System.out.println();
        for(int i: arr) {
            System.out.print(i + " ");
        }
    }
    public void bubbleSort(int[] arr) {
        // 第一轮循环
        for(int j=0; j arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

// 运行结果:
3 44 38 5 47 15 36 26 27 2 46 4 19 50 48 
3 38 5 44 15 36 26 27 2 46 4 19 47 48 50 
Process finished with exit code 0


3. 针对所有的元素重复以上的步骤,除了最后一个。

4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

public class BubbleSort {
    @Test
    public void testBubbleSort() {
        int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
        for (int i : arr) {
            System.out.print(i + " ");
        }
        bubbleSort(arr);
        System.out.println();
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
    public void bubbleSort(int[] arr) {
        for (int i = arr.length - 1; i > 0; i--) {
            // 第一轮循环
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}
// 运行结果:
3 44 38 5 47 15 36 26 27 2 46 4 19 50 48 
2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
Process finished with exit code 0

可以看到上面两个for循环,事件复杂度为O(n2),冒泡排序是比较简单的排序算法,但是在很多地方都用得到,比如在斗地主游戏中,当然牌多的话是不适合使用冒泡排序的,一般小于2^3左右使用该算法。


优化

在开始的动图中,我们看到最后的时候,不知道有没有发现前面几项是已经排好顺序的,而且动画也没有因为前面还有几项数据而继续下去而是直接完成了排序的算法,

接下来我们把程序稍作改动,看到调换的过程:

public class BubbleSort {
    @Test
    public void testBubbleSort() {
        int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
        print(arr);
        bubbleSort(arr);
        System.out.println();
    }
    public void bubbleSort(int[] arr) {
        int count = 0;
        for (int i = arr.length - 1; i > 0; i--) {
            // 第一轮循环
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            count++;
            System.out.print("第 " + count + " 次调换结果为:");
            print(arr);
        }
    }
    public void print(int[] arr) {
        for (int k : arr) {
            System.out.print(k + " ");
        }
        System.out.println();
    }
}

// 运行结果为:
3 44 38 5 47 15 36 26 27 2 46 4 19 50 48 
第 1 次循环结果为:3 38 5 44 15 36 26 27 2 46 4 19 47 48 50 
第 2 次循环结果为:3 5 38 15 36 26 27 2 44 4 19 46 47 48 50 
第 3 次循环结果为:3 5 15 36 26 27 2 38 4 19 44 46 47 48 50 
第 4 次循环结果为:3 5 15 26 27 2 36 4 19 38 44 46 47 48 50 
第 5 次循环结果为:3 5 15 26 2 27 4 19 36 38 44 46 47 48 50 
第 6 次循环结果为:3 5 15 2 26 4 19 27 36 38 44 46 47 48 50 
第 7 次循环结果为:3 5 2 15 4 19 26 27 36 38 44 46 47 48 50 
第 8 次循环结果为:3 2 5 4 15 19 26 27 36 38 44 46 47 48 50 
第 9 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
第 10 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
第 11 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
第 12 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
第 13 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
第 14 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
Process finished with exit code 0

可以看到,当第九次调换完了之后,我们的整个数组是已经完成了排序的,但是程序并不知道当前数组是已经排序好的,所以,我们得让他知道,前面的数据已经好了,你别给我傻乎乎的又循环调换一次啦!

接下来我们给一个标志位,当每一次调换完之后,这个标志位如果没变的话,则说明前面的数据是有序的,如果改变的话说明是无序的。
public class BubbleSort {
    @Test
    public void testBubbleSort() {
        int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
        print(arr);
        bubbleSort(arr);
        System.out.println();
    }
    public void bubbleSort(int[] arr) {
        int count = 0;
        boolean flag;
        for (int i = arr.length - 1; i > 0; i--) {
            // 第一轮循环
            flag = false;
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = true;
                }
            }
            count++;
            System.out.print("第 " + count + " 次循环结果为:");
            print(arr);
            if (!flag) {
                break;
            }
        }
    }
    public void print(int[] arr) {
        for (int k : arr) {
            System.out.print(k + " ");
        }
        System.out.println();
    }
}

// 运行结果为:
3 44 38 5 47 15 36 26 27 2 46 4 19 50 48 
第 1 次循环结果为:3 38 5 44 15 36 26 27 2 46 4 19 47 48 50 
第 2 次循环结果为:3 5 38 15 36 26 27 2 44 4 19 46 47 48 50 
第 3 次循环结果为:3 5 15 36 26 27 2 38 4 19 44 46 47 48 50 
第 4 次循环结果为:3 5 15 26 27 2 36 4 19 38 44 46 47 48 50 
第 5 次循环结果为:3 5 15 26 2 27 4 19 36 38 44 46 47 48 50 
第 6 次循环结果为:3 5 15 2 26 4 19 27 36 38 44 46 47 48 50 
第 7 次循环结果为:3 5 2 15 4 19 26 27 36 38 44 46 47 48 50 
第 8 次循环结果为:3 2 5 4 15 19 26 27 36 38 44 46 47 48 50 
第 9 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
第 10 次循环结果为:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 
Process finished with exit code 0

当程序运行到第九次的时候,flag是为true的,所以会正常走下面的流程;当运行到第十次的时候,flag为false,所以走了下面的break。

总结

冒泡排序是算法中比较简单的过程,同时也是比较实用的排序算法,根据原理,我们可以理清自己的逻辑一步步实现。

你可能感兴趣的:(面试题一天一题——第八天 · (手写冒泡排序及优化))