这一篇文章小编主要通过图文结合的形式带大伙了解算法的实现原理,当然让这块也是我们面试经常会被问到的地方。对于大部分公司的面试来说,排序的内容已经足以应付了,由此为了更好的符合大众需求,排序的内容是最多的。当然如果你还想冲击更好的公司,最好是能够将整篇文章好好的阅读和理解。
注意:为了方便大伙手机阅读,文中较长的代码片段会用图片代替!
![29cb5f2afc9f97cc36905a0317e0db79.png](https://i-blog.csdnimg.cn/blog_migrate/abfd53a4dc55c0b905f504442ecb2525.jpeg)
位运算
在进入正题之前,我们先来学习一下位运算的内容。因为位运算在算法中很有用,速度可以比四则运算快很多。
在学习位运算之前应该知道十进制如何转二进制,二进制如何转十进制。这里说明下简单的计算方式
- 十进制33可以看成是32+1,并且33应该是六位二进制的(因为33近似32,而32是2的五次方,所以是六位),那么十进制33就是100001,只要是2的吃饭,那么就是1,否则都是0。
- 二进制100001同理,首位是2^5,末位是2^0,现价得出33。
左移 <<
10 <<1 // ->20
左移就是将二进制全部往左移动,10在二进制中标识为1010,左移以为后变成10100,转换为十进制就是20,所以基本可以把左移看成一下公司a * (2 ^ b)。
算数右移 >>
10 >>1 // ->5
算数右移就是将二进制全部往右移动并去除多余的右边,10在二进制中表示为1010,右移一位后变成101,转换为十进制就是5,所以基本可以把右移看成一下公式 int v = a / (2 ^ b)。
右移很好用,比如可以用在二分算法中取中间值:
13 >> 1 // ->6
按位操作
1、按位与
每一位都为1,结果才为1。
8 & 7 // ->0// 1000 & 0111 -> 0000 -> 0
2、按位或
其实一位为1,结果就是1。
8 | 7 // -> 15// 1000 & 0111 -> 1111 -> 15
2、按位异或
每一位都不用,结果才为1。
8 | 7 // -> 158 ^ 8 = 0//1000 ^ 0111 -> 1111 -> 15//1000 ^1000 -> 0000 -> 0
从以上代码中可以发现按位异或就是不进位加法。
排序
冒泡排序
原理:从第一个元素开始,把当前元素和下一个索引元素进行比较。如果当前元素大,那么就交换位置,重复操作直到比较到最后一个元素,那么此时最后一个元素就是该数组中最大的数。下一轮重复以上操作,但是此时最后一个元素已经是最大数了,所以不需要再比较最后一个元素,只需要比较到 length - 2 的位置,可以看下面的动态图。
![b739454fa712575971fc08994697a0f3.gif](https://i-blog.csdnimg.cn/blog_migrate/ce091110b3ac341b80451b420c9ed99c.gif)
代码实现:
function bubble(array) { checkArray(array); for (let i = array.length - 1; i > 0; i--) { // 从 0 到 `length - 1` 遍历 for (let j = 0; j < i; j++) { if (array[j] > array[j + 1]) swap(array, j, j + 1) } } return array;}
该算法的操作次数是一个等差数列 n + (n - 1) + (n - 2) + 1 ,去掉常数项以后得出时间复杂度是 O(n * n)。
插入排序
原理:第一个元素默认是已排序元素,取出下一个元素和当前元素比较,如果当前元素大就交换位置。那么此时第一个元素就是当前的最小数,所以下次取出操作从第三个元素开始,向前对比,重复之前的操作。
![1d71246a5523775171069f6457ce7025.gif](https://i-blog.csdnimg.cn/blog_migrate/b794d8fe95eaaa5c8cd022e6e843c52e.gif)
代码实现:
function insertion(array) { checkArray(array); for (let i = 1; i < array.length; i++) { for (let j = i - 1; j >= 0 && array[j] > array[j + 1]; j--) swap(array, j, j + 1); } return array;}
该算法的操作次数是一个等差数列 n + (n - 1) + (n - 2) + 1 ,去掉常数项以后得出时间复杂度是 O(n * n)。
选择排序
原理:遍历数组,设置最小值的索引为 0,如果取出的值比当前最小值小,就替换最小值索引,遍历完成后,将第一个元素和最小值索引上的值交换。如上操作后,第一个元素就是数组中的最小值,下次遍历就可以从索引 1 开始重复