前端开发必备技能 —— 手写系列之数据结构
数据结构
二叉树
二叉树中序遍历
二叉树前序遍历
二叉树后序遍历
判断二叉树是否为对称二叉树
三级目录
算法
排序
冒泡排序
- 第一轮大循环,将本数组最大的数移到最后面
- 第二轮大循环,将本数组第二大的数移到倒数第二个
- 不断地交换,不断地把当轮循环中最大的数往后挪
- 时间复杂度O(n^2),空间复杂度O(1)
function bubbleSort(array){
for (let i = 0; i < array.length; i++){
let isComplete = true;
for (let j = 0; j < array.length-j-1; j++){
if(array[j]>array[j+1]){
[array[j],array[j+1]] = [array[j+1],array[j]];
isComplete = false;
}
}
if (isComplete) {
break;
}
}
return array;
}
选择排序
- 进行n-1次大循环
- 每次大循环,目的在于遍历当前大循环元素后面的所有元素,以查找出最小的元素
- 不断把最小的元素与当前元素交换
- 时间复杂度O(n^2),空间复杂度O(1)
function selectionSort(array) {
for (let i = 0; i < array.length - 1; i++) {
let minIndex = i;
for (let j = i + 1; j < array.length; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
[array[i], array[minIndex]] = [array[minIndex], array[i]];
}
}
插入排序
- 从数组的第二个开始遍历,直至最后一个
- 大循环遍历目的在于,将当前目标元素插到前面合适的位置
- 如果比前面的元素小,就不断交换位置
- 直至它比前面的元素都要大,则这就是它合适的位置。
- 时间复杂度O(n^2),空间复杂度O(1)
function insertSort(array) {
for (let i = 1; i < array.length; i++) {
let target = i;
for (let j = i - 1; j >= 0; j--) {
if (array[target] < array[j]) {
[array[j], array[target]] = [array[target], array[j]]
target = j;
} else {
break;
}
}
}
return array;
}
快速排序
function quickSort(array, start, end) {
if (end - start < 1) {
return;
}
const target = array[start];
let l = start;
let r = end;
while (l < r) {
while (l < r && array[r] >= target) {
r--;
}
array[l] = array[r];
while (l < r && array[l] < target) {
l++;
}
array[r] = array[l];
}
array[l] = target;
quickSort(array, start, l - 1);
quickSort(array, l + 1, end);
return array;
}
手撕JavaScript/ES6
实现call
- ① 通过Function.prototype,可以使得所有函数都可以访问myCall
- ② test.myCall(obj),隐式绑定,使得myCall内部的this指向test函数
- ③ context[fn] = this;this赋给context的fn属性
- ④ contextfn;执行。test函数执行,不过此时test的this是指向context的
Function.prototype.myCall = function (context = window, ...args) {
context = context || window;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
}
关于第三点和第四点的描述,与下面代码的道理是一样的:
var name = 'kabukiyo';
var obj = {
name : 'testest'
}
function test(){
console.log(this.name);
}
test() // kabukiyo
obj.fn = test();
obj.fn() // testest
- 把一个函数丢给某个对象的属性
- 对象的属性执行,相当于执行这个函数,不过此时该函数的this就指向该对象了(this如愿以偿地改变了)
实现apply
apply接收的是数组
Function.prototype.myApply = function (context = window, args) {
context = context || window;
const fn = Symbol();
context[fn] = this;
let result;
if (Array.isArray(args)) {
result = context[fn](...args);
} else {
result = context[fn]();
}
delete context[fn];
return result;
}
实现bind
Function.prototype.myBind = function (context,...args1) {
const _this = this
return function F(...args2) {
return _this.apply(context, args1.concat(args2))
}
}
var obj = {
z: 1
};
function fn(x, y) {
alert( x + y + this.z);
};
var bound = fn.bind_(obj, 1);
bound(2);
Function.prototype.bind_ = function (obj) {
//第0位是this,所以得从第一位开始裁剪
var args = Array.prototype.slice.call(arguments, 1);
var fn = this;
return function () {
//二次调用我们也抓取arguments对象
var params = Array.prototype.slice.call(arguments);
//注意concat的顺序
fn.apply(obj, args.concat(params));
};
};