你知道哪些算法?讲一下它的内部实现过程?

上一文章我们介绍了数据结构的知识,数据结构属于计算机存储的基础,有了它才能更好地将数据进行存储。而算法可以这样理解:它是为数据结构服务的,使用合适的算法可以更快地操作和查询这些数据。

算法的内容有很多,随随便便一本算法书有个 700 页到 1500 页也是很平常的事,因此我们在这里不能把所有的算法问题全部讲到,即使专门再开设一个算法专栏,也只能挑重点的讲。那么我们好钢就要用在刀刃上,这里会把面试中经常出现的和平常工作中使用频率最高的算法,拿出来给大家分享。

你知道哪些算法?讲一下它的内部实现?

典型回答

最常见、最基础的算法是二分法,它是二分查找算法的简称(Binary Search Algorithm),也叫折半搜索算法或对数搜索算法。它是一种在有序数组中查找某一特定元素的搜索算法,顾名思义,是将一组有序元素中的数据划分为两组,通过判断中间值来确认要查找值的大致位置,然后重复此过程进行元素查询。

例如,我们要查询 1-100 中的某个数值,比如我们要查询的数值为 75,如果按照顺序从 1 开始一直往后排序对比的话,需要经历 75 次,才能查询到我们想要的数据;而如果使用二分法,则会先判断 50(1~100 的中间值)和 75 哪个大,然后就能确定要查询的值是在 50-100 之间,最后再进行二分,用 75 和 75 进行比较,结果发现此值就是我们想要找的那个值,于是我们只用了两步就找到了要查询的值,这就是算法的“魔力”。

在这里插入图片描述
在这里插入图片描述
二分查找算法的实现代码如下:

public class AlgorithmExample {

    public static void main(String[] args) {

        // 要查询的数组

        int[] binaryNums = new int[100];

        for (int i = 0; i < 100; i++) {

            // 初始化数组(存入 100 个数据)

            binaryNums[i] = (i + 1);

        }

        // 要查询的数值

        int findValue = 75;

        // 调用二分查找算法

        int binaryResult = binarySearch(binaryNums, 0, binaryNums.length - 1, findValue);

        // 打印结果

        System.out.println("元素的位置是:" + (binaryResult + 1));

    }

    /**

     * 二分查找算法(返回该值第一次出现的位置)

     * @param nums      查询数组

     * @param start     开始下标

     * @param end       结束下标

     * @param findValue 要查找的值

     * @return int

     */

    private static int binarySearch(int[] nums, int start, int end, int findValue) {

        if (start <= end) {

            // 中间位置

            int middle = (start + end) / 2;

            // 中间的值

            int middleValue = nums[middle];

            if (findValue == middleValue) {

                // 等于中值直接返回

                return middle;

            } else if (findValue < middleValue) {

                // 小于中值,在中值之前的数据中查找

                return binarySearch(nums, start, middle - 1, findValue);

            } else {

                // 大于中值,在中值之后的数据中查找

                return binarySearch(nums, middle + 1, end, findValue);

            }

        }

        return -1;

    }

}

以上程序的执行结果为:

元素的位置是:75

从上面的内容我们可以看出二分法虽然简单,但是也要满足一个特定的条件才行,那就是要使用二分法必须是有序排列的数值才行,不然是没办法实现二分法的。

除了二分法之外还有另一个比较常用的排序算法:冒泡排序。

冒泡排序(Bubble Sort)又被称为泡式排序,它是指重复走访要排序的数列,每次比较两个元素,如果顺序不对就进行交换,直到没有被交换的元素为止,这样就完成了一次冒泡排序。

为了让大家更好地理解冒泡排序,我录制了一个 gif 图片用于展示冒泡排序的执行过程,如下图所示:

在这里插入图片描述
由上图可以看出,冒泡排序的关键执行流程是:依次对比相邻的两个数字,如果前面的数字大于后面的数字,那么就将前、后两个数字进行位置交换;这样每次对比完一轮数据之后,能找出此轮最大的数字并放置到尾部,如此重复,直到没有可以交换的数据为止,这样就完成了冒泡排序。

接下来我们就使用 Java 代码来实现一个冒泡排序算法,实现代码如下:

import java.util.Arrays;

public class AlgorithmExample {

    public static void main(String[] args) {

        // 待排序数组

        int[] nums = {33, 45, 11, 22, 12, 39, 27};

        bubbleSort(nums);

        // 打印排序完数组

        System.out.println(Arrays.toString(nums));

    }

    /**

     * 冒泡排序

     */

    private static void bubbleSort(int[] nums) {

        for (int i = 1; i < nums.length; i++) {

            for (int j = 0; j < nums.length - i; j++) {

                if (nums[j] > nums[j + 1]) {

                    // 前面数字大于后面的数字,执行位置交换

                    int temp = nums[j];

                    nums[j] = nums[j + 1];

                    nums[j + 1] = temp;

                }

            }

        }

    }

}

以上程序的执行结果为:

[11, 12, 22, 27, 33, 39, 45]

从以上结果可以看出,冒泡排序算法的执行成功了,结果也符合我们的预期。

冒泡排序和二分法属于程序员必须掌握的两种最基础的算法了,如果连这两个算法都不知道或者都不能手写这两种算法的话,可能会给面试官留下非常不好的印象。因为二者都属于基础中的基础了,其实只要理解了两种算法的核心思想,再手写代码也不是什么难事,如果实在写不出具体的代码,最起码要做到能写出伪代码的程度。

●如何优化冒泡排序算法?

●是否还知道更多的算法?

知识扩展

冒泡排序优化

从上面冒泡排序的 gif 图片可以看出,在最后一轮对比之前,数组的排序如下图所示:

在这里插入图片描述
从图片可以看出,此时数组已经完全排序好了,但是即使这样,冒泡排序还是又执行了一次遍历对比,如下图所示:

在这里插入图片描述
因此我们就可以想办法去掉无效的遍历,这样就可以优化冒泡排序的执行效率了。

我们可以在第一层循环内加一个判断标识,每次赋值为 true,假如在第二层循环(内层循环)时执行了位置交换,也就是 if 中的代码之后,我们把此值设置成 false;如果执行完内层循环判断之后,变量依然为 true,这就说明没有可以移动的元素了,冒泡排序可以结束执行了,优化后的代码如下所示:

import java.util.Arrays;

public class AlgorithmExample {

    public static void main(String[] args) {

        // 待排序数组

        int[] nums = {33, 45, 11, 22, 12, 39, 27};

        bubbleSort(nums);

        // 打印排序完数组

        System.out.println(Arrays.toString(nums));

    }

    /**

     * 冒泡排序

     */

    private static void bubbleSort(int[] nums) {

        for (int i = 1; i < nums.length; i++) {

            // 判断标识

            boolean flag = true;

            for (int j = 0; j < nums.length - i; j++) {

                if (nums[j] > nums[j + 1]) {

                    // 前面数字大于后面的数字,执行位置交换

                    int temp = nums[j];

                    nums[j] = nums[j + 1];

                    nums[j + 1] = temp;

                    // 执行了位置交换,更改标识

                    flag = false;

                }

            }

            if (flag) {

                // 没有可以移动的元素了,跳出循环

                break;

            }

        }

    }

}

以上程序的执行结果为:

[11, 12, 22, 27, 33, 39, 45]

此结果说明,冒泡排序的执行符合我们的预期,执行成功。

插入排序

插入排序(Insertion Sort)算法是指依次循环当前的列表,通过对比将每个元素插入到合适的位置,它的具体执行过程,如下图所示:

在这里插入图片描述
插入算法的具体实现代码如下:

public class AlgorithmExample {

    public static void main(String[] args) {

        int[] insertNums = {4, 33, 10, 13, 49, 20, 8};

        // 插入排序调用

        insertSort(insertNums);

        System.out.println("插入排序后:" + Arrays.toString(insertNums));

    }

    /**

     * 插入排序

     */

    private static void insertSort(int[] nums) {

        int i, j, k;

        for (i = 1; i < nums.length; i++) {

            k = nums[i];

            j = i - 1;

            // 对 i 之前的数据,给当前元素找到合适的位置

            while (j >= 0 && k < nums[j]) {

                nums[j + 1] = nums[j];

                // j-- 继续往前寻找

                j--;

            }

            nums[j + 1] = k;

        }

    }

}

以上程序的执行结果为:

插入排序后:[4, 8, 10, 13, 20, 33, 49]

选择排序

选择排序(Selection Sort)算法是指依次循环数组,每轮找出最小的值放到数组的最前面,直到循环结束就能得到一个有序数组,它的执行过程如下图所示:

在这里插入图片描述
选择排序的具体实现代码如下:

public class AlgorithmExample {

    public static void main(String[] args) {

        int[] insertNums = {4, 33, 10, 13, 49, 20, 8};

        // 调用选择排序

        selectSort(insertNums);

        System.out.println("选择排序后结果:" + Arrays.toString(insertNums));

    }

    /**

     * 选择排序

     */

    private static void selectSort(int[] nums) {

        int index;

        int temp;

        for (int i = 0; i < nums.length - 1; i++) {

            index = i;

            for (int j = i + 1; j < nums.length; j++) {

                if (nums[j] < nums[index]) {

                    index = j;

                }

            }

            if (index != i) {

                temp = nums[i];

                nums[i] = nums[index];

                nums[index] = temp;

            }

            System.out.print("第" + i + "次排序:");

            System.out.println(Arrays.toString(nums));

        }

    }

}

以上程序的执行结果为:

0次排序:[4, 33, 10, 13, 49, 20, 8]1次排序:[4, 8, 10, 13, 49, 20, 33]2次排序:[4, 8, 10, 13, 49, 20, 33]3次排序:[4, 8, 10, 13, 49, 20, 33]4次排序:[4, 8, 10, 13, 20, 49, 33]5次排序:[4, 8, 10, 13, 20, 33, 49]

选择排序后结果:[4, 8, 10, 13, 20, 33, 49]

小结

本着将一个知识点吃透的原则,本课时我们总共介绍了四种算法:冒泡排序算法、二分法、插入排序算法、选择排序算法等,并且还讲了冒泡排序算法的优化。但由于篇幅的原因,这些只能介绍一些常用的算法,如果想要更加深入地学习算法,还需要你投入更多的时间来学习,推荐阅读《算法》(第 4 版)的内容。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andrew.J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值