选择排序
-
选择一个最小的数,插在数组第一个位置;然后选择第二小的数,插在数组第二个位置...
-
先假设第一个数是数组中最小的数,然后从头开始遍历;查找第一个数之后的元素,看是否有比最小数还小的最小数,如果有,就把索引值记录下来;如果找到后,就将该元素与最小值的位置进行交换;找完后再从第二个数开始往后找(因为第一个数已经是最小值了),寻找方法跟之前一样,如此往复
var arr = [ 4, 8, 5, 2, 9, 7, 3, 1, 6 ]; for(var i = 0; i < arr.length - 1; i++){ var minIndex = i; for(var j = i + 1; j < arr.length; j++){ if(arr[j] < arr[minIndex]) minIndex = j; } if(minIndex !== i){ var tmp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = tmp; } } console.log(arr);
冒泡排序
-
冒泡顾名思义,即像泡泡一样,轻的升到上面
-
我们需要将数组中的数进行两两比较,若前一个数比后一个数大,则进行交换;一轮比较换后,最后一个数就是最大的数;然后再从头开始再次进行两两比较,将大数往后进行交换。所以一共需要两重循环,第一重循环用于控制一共进行多少次两两比较,第二重循环用于控制两两比较。第一重一共需要循环
length - 1次,第二重一共需要length - 1 - i次,因为每循环完一次,就会多一个数不需要参与比较,即被沉到右边的数var arr = [ 4, 8, 5, 1, 9, 7, 2, 3, 6 ]; /* 两两进行比较,若前面的大于后面的,则进行交换,这样大数就会沉到底部 一共有 length 个元素,两两进行比较,所以只需要进行 length - 1 次循环 */ for(var i = 0; i < arr.length - 1; i++){ /* 用于标记是否交换过数组,若交换过 flag 的值为真,说明现在的数组可能还是乱序的,需要继 续循环比较交换;若没有交换过 flag 的值为假,说明此时的数组已经是有序的了,不需要再循 环比较了。也就是假如一共需要循环 7 次,当在第五次的时候数组已经是有序的了,此时便可以 不再循环了,因为不需要再进行交换数组了,接着循环也没有意义 */ var flag = false; /* 从第一个数开始比较,若比后面的大,则进行交换 第一轮循环结束后,最后一位就是数组中最大的数, 下一次循环的时候不需要参与比较 所以第二层循环的次数为 arr.length - 1 - i */ for(var j = 0; j < arr.length - 1 - i; j++){ if(arr[j] > arr[j + 1]){ var tmp = arr[j]; arr[j] = arr[j +1]; arr[j + 1] = tmp; flag = true; } } if(!flag) break; } console.log(arr);
计数排序
-
将数组中的数进行统计,看某个数一共有多少个,将其装入一个新的数组,将原数组清空,然后再重新填回原来的数组
-
计算某个数有多少个时,将该数作为新数组的下标,判断新数组中该位置的数是否为0,若为0,将该位置置一;否则进行自增操作,表示有 n 个该数(原数组中有重复元素)
-
回填时,从头开始遍历新数组,下标就是需要回填的数,即回填的回去的数一定是有序的,因为是按下标依次回填(新数组的下标就是要回填的数);若该下标所在的位置存放的数为0,说明原数组中没有该数,跳过;否则将其填回原数组,有多少个填多少个,即看新数组该位置存放的是几
var arr = [ 10, 20, 10, 11, 3, 5, 7, 4, 3, 2, 1, 3, 4, 5, 6, 11 ]; var temp = []; //用 temp 数组的值表示该数有多少个 for(var i = 0; i < arr.length; i++){ //把数组中的值作为 temp 数组的索引值 var index = arr[i]; //查找该索引位置,若该数已经存在在 temp 中,则将数组值加一,否则将值置一 temp[index] ? temp[index]++ : temp[index] = 1; } arr.length = 0; //清空数组可直接将数组长度置为0 for(var i = 0; i < temp.length; i++){ //若该位置没有数,也就是说原数组中没有 i 这个数,就跳过,看下一个数有没有 if(!temp[i]) continue; //将某个数的总个数记录下来 var count = temp[i]; //将要回填的数记录下来,要回填的数就是 i var data = i; for(var j = 0; j < count; j++){ arr[arr.length] = data; //下标等于数组长度等于在数组末尾添加元素,因为数组中最后一个数的下标是 length - 1 } } console.log(arr);
快速排序
-
找到数组中中间的数字(称其
center),然后和数组中其他元素进行比较,若比它小,就放到一个数组中(称为左数组,将其放在center左面),否则放到另一个数组中(称为右数组,将其放在center右边),即center左边的都是比它小的数,右边都是比它大的数;然后再对左右数组进行重复操作,直到只剩一个元素或者没有元素的时候停止;此时将数组的合并起来,该数组就是升序的var arr = [ 4, 7, 5, 2, 6, 3, 9, 1, 8 ]; function quick_sort(a){ //如果数组的长度小于等于 1,就可以停止递归了 if(a.length <= 0) return a; //取出数组中间的数字 var center = a.splice(parseInt(a.length / 2), 1)[0]; //left 数组用于存放比 center 小的数,right 数组用于存放比 center 大的数 var left = [], right = []; for(var i = 0; i < arr.length; i++){ //将比 center 小的数放到 left 数组中,大的放到 right 数组中 a[i] < center ? left.push(a[i]) : right.push(a[i]); } /* 此时 left 数组,center,right 数组整体是有序,但 left 和 right 数组内 是无序的,所以需要对 left 和 right 数组进行刚才的重复操作,可以使用递归来 实现,当数组中的元素个数小于等于 1 的时候,就是递归结束的时候。因为此时只剩 一个或零个元素,不需要再划分 left 和 right 数组了。将值进行返回然后进行拼接 */ return [...quick_sort(left), center, ...quick_sort(right)]; }
插入排序
- 对于数
a,从后往前扫描数组,找到相应的顺序插入 - 遍历整个数组,从第 1 个位置开始,记作
a往前开始比较,若前面的数比他大就继续往前比较(没有走到最开始的位置并且也没有发现比他小的数),当找到比他小的数时停止,记作b,此时b < a,也就是说把b放在a的后面数组会趋向于有序;将之前比较过的数依次向后移一位,将b后面的位置空出来用于将a插入进去
var arr = [ 4, 5, 2, 7, 6, 3, 9, 1, 8 ];
for(var i = 0; i < arr.length; i++){
//将数组中的某个值记录下来,后面用于插入
var temp = arr[i];
//将 temp 前面的数的下标记录下来,用于循环比较,因为是向前比较
var j = i - 1;
//没有发现比 temp 小的数且也没有找到数组最开始的位置,就继续向前比较
while(j >= 0 && temp < arr[j]){
//将 temp 前面的数依次向后移
arr[j + 1] = arr[j];
//没移完一次就将 j 减一,用于下一次比较
j--;
}
//循环结束时,多减了一次,需要加回来
arr[j + 1] = temp;
}
console.log(arr);