关于算法的东西,本来不应该交给javascript来做,因为对算法和数据结构的理解,并不会因为用自己熟悉的语言实现常用数据结构和算法而得到多大的提升,不过这一过程终归是有一些好处的,对于一些非科班出身的人来讲。
首先解释一下冒泡排序的机制:遍历要排序的数列,比较相邻两个元素,如果他们的顺序和我们想要的不一致,就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。冒泡排序的做法有小数上浮 或者 大数下沉两种 ,这里只提及大数下沉的实现。
外层循环的作用是,提取出目前未排序数组中最大的数,放置于已排数据的左边。也就是说我们第一次外层循环,是把最大数的位置交换到数组的最右边,第二次外层循环是把次大数交换到数组的次右边,依次类推。而且一个数组的长度为length,我们只需要提出 length-1 个大数,则数组的 第一个 必定为 未被提取的 最小数,那么在外层for循环的条件判断 i 的取值范围也就可以理解了。
而内层循环的作用就是实现我们想要的大数下沉的过程。每次比较的是相邻两个数据,所以一个数组的长度为length,我们只需要做 length-1 次相邻的比较,就可以实现大数下沉,而 之前循环 已经沉淀的大数 并不需要再进行 排序了 , 所以内层循环的 条件判断 j 的取值范围 也容易理解了。
接下来我们要做数据交换了,我们想做的是 大数沉淀, 也就是 当相邻两个数据,左边比右边大时,交换位置,这里提供了三种方法。
下面发一段关于冒泡排序的代码吧。
1 function bubbleSort (arr) { 2 for (var i = 0; i < arr.length-1; i++) { 3 for (var j = 0; j < arr.length-1-i; j++) { 4 if (arr[j] > arr[j+1]) { 5 /* 设置第三方变量来用于数据交换,且这个变量放在循环的外面性能要好 6 var temp = arr[j]; 7 arr[j] = arr[j+1]; 8 arr[j+1] = temp; 9 */ 10 11 // 利用加法来实现两个数据的交换 12 // arr[j] = arr[j] + arr[j+1]; 13 // arr[j+1] = arr[j] - arr[j+1]; 14 // arr[j] = arr[j] - arr[j+1]; 15 16 // 利用位运算实现两个数据的交换 17 arr[j] = arr[j]^arr[j+1]; 18 arr[j+1] = arr[j]^arr[j+1]; 19 arr[j] = arr[j]^arr[j+1]; 20 } 21 }; 22 }; 23 return arr; 24 }
我们可以看到,第一种方法需要开辟新的内存空间,所以这个第三方变量为全局变量时性能较好,这一种方法是使用最多的方法,也最易于理解。
第二种方法,则是利用了加法实现了两个数据的交换,也不难理解,而且加法可以做,减法肯定也可以做,毕竟减法在某种意义上来讲,也是加法。
第三种方法使用了位运算,按位异或 XOR 由符号(^)表示,它是直接对数据在内存中的二进制形式进行运算。这里用到了按位异或的一个特性实现了数据的交换:一个数据按位异或另一个数两次等于它本身。它的效率要比上述两种方式的效率要高,但是用javascript想要高效率的处理数据本身就是一个笑话。
至此我们的冒泡就告一段落了,如有错漏的地方还请多多指正。