本次重温了四个算法:冒泡排序,希尔排序,插入排序,快速排序
首先创建一个公共的方法,交换两个数字在数组中的位置
function swap(array, index_1, index_2) {
let a = array[index_1];
array[index_1] = array[index_2];
array[index_2] = a;
return array;
}
- 冒泡排序
var arr = [2,3,4,5,1,23,0,6,9,8,7];
/**
- 循环遍历,将每一个值与后面的值进行对比,如果后面的值比当前值小,就交换位置,从而达到冒泡排序
- 每次需要循环 n-1, n-2, n-3, n-4, ..., 1, 一共n次
- 所以是 (n-1 + 1)*n / 2 =》 n^2/2舍去常数,也就是n^2
**/
Array.prototype.bubbling = function() {
for(let i = 0; i < this.length; i++) {
for(let j = i + 1; j < this.length; j++) {
let current = this[i];
let compare = this[j];
if(compare < current) {
swap(this, i, j);
}
}
}
return this;
}
-
希尔排序
希尔排序,是基于冒泡之上的,理念差不多,只不过从之前的每一个都要和后面的所有项对比改为,间隔着对比。 在一定程度上可以减少运算量。
例如
-
有数组 7 5 9 3 1 2 4,长度的一半向下取整为3,也就是说当前数字与 当前数字索引值+3的数字进行对比
1) 7 > 3 => 3 5 9 7 1 2 4
2) 5 > 1 => 3 1 9 7 5 2 4
3) 9 > 2 => 3 1 2 7 5 9 4
4) 7 > 4 => 3 1 2 4 5 9 7
这时4+3>length-1(6),所以本次循环结束 -
上次的间隔为3,第二次是 3/2 向下取整 为1,数组为 3 1 2 4 5 9 7 ***
1)3 > 1 => 1 3 2 4 5 9 7
2) 3 > 2 => 1 2 3 4 5 9 7
3) 3 < 4
4) 4 < 5
5) 5 < 9
6) 9 > 7 => 1 2 3 4 5 7 9
这样下来,总共用了10次,如果用冒泡的话,需要 6+5+4+3+2+1,21次,少了11次
在我这个基础上有一个小改动,可以使这个数组的排序用的次数更多(也是我最初猜测的算法)
将当前数字与当前数字索引值+3改为 中间间隔3个
7 5 9 3 1 2 4
第一次:(间隔3个)
1)1 5 9 3 7 2 4
2)1 2 9 3 7 5 4
3)1 2 4 3 7 5 9
第二次:(间隔1个)
4)1 2 4 3 7 5 9
5)1 2 4 3 7 5 9
6)1 2 4 3 7 5 9
7)1 2 4 3 7 5 9
8)1 2 4 3 7 5 9
第三次:(间隔0个)
9 10 11 12 13 14 (重复***处的6个)
总共用了14次
我用了最笨的枚举法列了一下次数,大概看一下区别把。。
对比下来,怎么样都比冒泡次数少。
var arr = [2, 3, 4, 5, 1, 23, 0, 6, 9, 8, 7];
Array.prototype.hillSort = function () {
let gap = Math.floor(this.length / 2);
while (gap >= 1) {
for (let i = 0; i < this.length - gap; i++) {
if (this[i] > this[i + gap]) {
swap(this, i, gap + i);
}
}
gap = Math.floor(gap / 2);
}
return this;
};
-
插入排序
插入排序,类似于打扑克牌,摸牌阶段,你会去找到比摸到的这张牌小的和大的中间,插进去
例如:
手牌中有1,7,9,本次摸到了8,从后往前找,找到了9,9的前面有数字7,8比9小,比7大,于是就将8插入到7和9中间
如果手牌中只有1,则只需要跟他比较,并决定放在他前面 还是他后面
如果摸到的牌比手牌都小,就需要将该牌放在手牌最前方
Array.prototype.insertSort = function() {
let newList = [];
for(let i = 0; i < this.length; i++) {
const current = this[i];
console.log(current, newList)
if(newList.length === 0) {
newList.push(current);
} else {
for(let j = newList.length - 1; j >= 0; j--) {
let bigItem = newList[j]
if(current > bigItem) {
newList.push(current);
break;
} else {
if(j > 0) {
var smallItem = newList[j - 1];
if(current > smallItem) {
newList.splice(j, 0, current);
break;
}
} else {
newList.unshift(current)
}
}
}
}
}
return newList;
}
- 快速排序
假设 中间值为一个标准值,然后将其他的值跟他对比,然后放入左右两侧
然后再去子集中的中间值作为标准值,对比子集,分为左右两侧(重复操作)
直到子集长度为1或0时,结束循环
这个速度会比上面几个都快,网上说这个的时间复杂度为O(n*log2n)
Array.prototype.quickSort = function quickSort() {
function sortFn(array) {
if(array.length < 2) return array;
var middle = Math.floor(array.length / 2);
let newList = [...array];
let leftArr = [],
rightArr = [];
var [reference] = newList.splice(middle, 1);
for(let i = 0; i < newList.length; i++) {
let current = newList[i];
if(current < reference) {
leftArr.push(current);
} else {
rightArr.push(current);
}
}
return [...sortFn(leftArr), reference, ...sortFn(rightArr)]
}
return sortFn(this);
}
从网上搜的一张图
选择排序和冒泡排序比较相似,其他几个我也是刚听说,,之后在更新其他的几个算法吧~
归并排序,堆排序,计数排序,桶排序,基数排序
好好学习,天天向上!