【算法】七月算法打卡

news2024/11/18 10:25:41

# 2022-07-11

深拷贝

const copyObject = (obj = {}) => {
  let newObj = null
  if (typeof (obj) === 'object' && obj !== null) {
    newObj = obj instanceof Array ? [] : {}
    // 进入下一层进行递归
    for (let i in obj) newObj[i] = copyObject(obj[i])
  } else {
    newObj = obj
  }
  return newObj
}

// 测试
let obj = {
  id: 1,
  func: () => {
    console.log('func')
  },
  userInfo: {
    name: '浩浩',
    age: 23,
    birthday: '1999-05-29'
  },
  hobby: ['敲代码', '还是敲代码']
}

const newObj = copyObject(obj)

obj.userInfo.name = 'haohao'
obj.hobby[0] = '躺平'

console.log('旧值', obj);
console.log('新值', newObj)

在这里插入图片描述


# 2022-07-12

数组去重

let arr = [undefined, 2, null, 3, 4, undefined, null, 2, 7, 1, 2, 4, 5]

// 方法一
let a = []
arr.forEach(item => {
  if (!a.includes(item)) a.push(item)
})
console.log("方法一:", a)

// 方法二
let b = Array.from(new Set(arr))
console.log("方法二:", b)

在这里插入图片描述


# 2022-07-13

数组扁平化

function flatter(arr) {
  if (!arr.length) return;
  
  return arr.reduce((pre, cur) => {
    return Array.isArray(cur) ? [...pre, ...flatter(cur)] : [...pre, cur]
  }, []);
}

// 测试
let arr = [1, 2, [1, [2, 3, [4, 5, [6]]]]]
console.log(flatter(arr));

在这里插入图片描述


# 2022-07-14

延迟模拟定时

setTimeout (function () {
  eventFunc();
  setTimeout(arguments.callee, 500);
}, 500)

function eventFunc () {
  console.log("每隔0.5秒执行一次");
}

在这里插入图片描述


# 2022-07-15

基于 XMLHttpRequest 封装 Ajax

let XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
function ajax(option) {
    // 请求 url
    let url = option.url;
    // 请求类型
    let type = option.type;
    // 请求参数
    let data = option.data;
    // 是否异步
    let async = option.async === false ? true : option.async;

    // 请求参数处理
    let reqParam = "";
    if (typeof data === "object") {
        for (let key in data) {
            reqParam += `key=${data[key]}&`
        }
        reqParam.slice(0, reqParam.length - 1);
    }

    // 获取 XMLHttpRequest 实例对象
    let xhr = new XMLHttpRequest();

    let flag = false;
    // 监听状态变化
    xhr.onreadystatechange = () => {
        
        // 请求前
        if (xhr.readyState <= 1) {
            
            if (option.beforeSend && !flag) {
                option.beforeSend();
                flag = true;
            }
        }

        // 请求完成
        if (xhr.readyState === 4) {
            let res;
            if (option.complete) option.complete();

            // 响应完成
            if (xhr.status === 200) {

                // 判断响应数据类型
                let resType = xhr.getResponseHeader("content-Type");

                // 响应数据处理
                if (resType.indexOf("json") > -1) {
                    res = JSON.parse(xhr.responseText);
                } else if (resType.indexOf("xml") > -1) {
                    res = xhr.responseXML;
                } else {
                    res = xhr.responseText;
                }

                if (option.success) option.success(res);
            } else {
                if (option.error) option.error(xhr)
            }
        } 
    }

    // get 请求
    if (type === "get" || type === "GET") {
        let fullUrl = reqParam.length == 0 ? url : `${url}?${reqParam}`;
        // 发起请求
        xhr.open(type, fullUrl, async);
        // 发送请求
        xhr.send(null);
    }

    // post 请求
    if (type === "post" || type === "POST") {
        // 发起请求
        xhr.open(type, url, async);
        // 设置请求头
        xhr.setRequestHeader("content-Type", "application/x-www-form-urlencoded");
        // 发送请求
        xhr.send(reqParam);
    }
}

// post
ajax({
    url: "http://39.104.61.32/api/user/register",
    type: "post",
    async: true,
    data: {
        userName: "aaa1231",
        password: "321",
        gender: 2
    },
    beforeSend: function () {
        console.log("api/user/register 请求前");
    },
    success: function (res) {
        console.log("api/user/register 请求成功", res);
    },
    error: function (error) {
        console.log("api/user/register 请求发生错误", error);
    },
    complete: function () {
        console.log("api/user/register 请求完成");
    }
})
// get
ajax({
    url: "http://39.104.61.32/api/atMe/number",
    type: "get",
    async: true,
    beforeSend: function () {
        console.log("api/atMe/number 请求前");
    },
    success: function (res) {
        console.log("api/atMe/number 请求成功", res);
    },
    error: function (error) {
        console.log("api/atMe/number 请求发生错误", error);
    },
    complete: function () {
        console.log("api/atMe/number 请求完成");
    }
})

在这里插入图片描述

基于 promise 封装 Ajax

let XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
function http(option) {
    let url = option.url;
    let data = option.url;
    let type = option.type;

    let reqParams = "";
    if (typeof data == "object") {
        for (let key in data) {
            reqParams += `&${key}=${data[key]}`
        }
        reqParams = reqParams.slice(0, str.length - 1);
    }

    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    let res;
                    let resType = xhr.getResponseHeader("content-Type");
                    if (resType.indexOf("jsonp") >= -1) {
                        res = JSON.parse(xhr.responseText);
                    } else if (resType.indexOf("xml") >= -1) {
                        res = xhr.responseXML;
                    } else {
                        res = xhr.responseText;
                    }
                    resolve(res);
                } else {
                    reject(xhr)
                }
            }
        }

        if (type == "get" || type == "GET") {
            let fullUrl = reqParams.length == 0 ? url : `${url}?${reqParams}`;
            xhr.open(type, fullUrl, true);
            xhr.send(null);
        }

        if (type == "post" || type == "POST") {
            xhr.open(type, url, true);
            xhr.setRequestHeader("content-Type", "application/x-www-form-urlencoded");
            xhr.send(reqParams)
        }
    })
}

// get
http({
    url: "http://39.104.61.32/api/atMe/number",
    type: "get"
}).then(res => {
    console.log("api/atMe/number", res)
}).catch(error => {
    console.log(error);
}) 

// post
http({
    url: "http://39.104.61.32/api/blog/create",
    type: "post",
    data: {
        content: "@fwz123123 - fwz123123 123"
    }
}).then(res => {
    console.log("app/user/login", res);
}).catch(error => {
    console.log(error);
})

在这里插入图片描述


# 2022-07-16

订阅事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>$on 和 $emit</title>
</head>
<body>
    <div class="wrapper">
        <div class="container">
            <h3>订阅者</h3>
            <div class="content">
                <div class="a"></div>
                <div class="b"></div>
                <div class="c"></div>
            </div>
            <div class="btn-group publish">
                <button class="btn" data-index="A">订阅事件A</button>
                <button class="btn" data-index="B">订阅事件B</button>
                <button class="btn" data-index="C">订阅事件C</button>
            </div>
            <div class="btn-group cancel-publish">
                <button class="btn" data-index="A">取消事件A</button>
                <button class="btn" data-index="B">取消事件B</button>
                <button class="btn" data-index="C">取消事件C</button>
            </div>
        </div>
        <div class="container">
            <h3>发布者</h3>
            <div class="content">
                <textarea></textarea>
            </div>
            <div class="btn-group send">
                <button class="btn" data-index="A">发布事件A</button>
                <button class="btn" data-index="B">发布事件B</button>
                <button class="btn" data-index="C">发布事件C</button>
            </div>
        </div>
    </div>
</body>
<script src="./js/EventBus.js"></script>
<script>
  let EB = new EventBus();
  let a;
  let b; 
  let c;
  // 订阅事件
  document.querySelector('.publish').addEventListener("click", (e) => {
      if (e.target.tagName == "BUTTON") {
          switch(e.target.dataset.index) {
              case "A":
                  document.querySelector(".container:first-child .content .a").innerHTML = "已经订阅事件A 等待发布者发布事件";
                  a = EB.$on('A', (value) => {
                      document.querySelector(".container:first-child .content .a").innerHTML = "订阅事件A-触发,内容为:"+ value;
                  });
              break;
              case "B":
                  document.querySelector(".container:first-child .content .b").innerHTML = "已经订阅事件B 等待发布者发布事件";
                  b = EB.$on('B', (value) => {
                      document.querySelector(".container:first-child .content .b").innerHTML = "订阅事件B-触发,内容为:"+ value;
                  });
              break;
              case "C":
                  document.querySelector(".container:first-child .content .c").innerHTML = "已经订阅事件C 等待发布者发布事件";
                  c = EB.$on('C', (value) => {
                      document.querySelector(".container:first-child .content .c").innerHTML = "订阅事件C-触发,内容为:"+ value;
                  });
              break;
          }
      }
  });
  // 取消订阅事件
  document.querySelector('.cancel-publish').addEventListener("click", (e) => {
      if (e.target.tagName == "BUTTON") {
          switch(e.target.dataset.index) {
              case "A":
                  EB.$off('A', a);
                  document.querySelector(".container:first-child .content .a").innerHTML = "";
              break;
              case "B":
                  EB.$off('B', b);
                  document.querySelector(".container:first-child .content .b").innerHTML = "";
              break;
              case "C":
                  EB.$off('C', c);
                  document.querySelector(".container:first-child .content .c").innerHTML = "";
              break;
          }
      }
  })

  document.querySelector('.send').addEventListener("click", (e) => {
      if (e.target.tagName == "BUTTON") {
          
          let value = document.querySelector("textarea").value || '默认值'
          let flag;
          switch(e.target.dataset.index) {
              case "A":
                  flag = EB.$emit('A', value);
              break;
              case "B":
                  flag = EB.$emit('B', value);
              break;
              case "C":
                  flag = EB.$emit('C', value);
              break;
          }
          if (flag == -1) alert("订阅者没有订阅事件"+ e.target.dataset.index);
      }
  })
</script>
</html>
class EventBus {
  constructor() {
      this.callbackId = 0;
      this.eventObj = {}; // 所有订阅事件
  }
  // 订阅事件
  $on(name, callback) {
      if (!this.eventObj[name]) this.eventObj[name] = []
      const id = this.callbackId++;
      this.eventObj[name][id] = callback;
      return id;
  }
  // 取消订阅事件
  $off(name, id) {
      delete this.eventObj[name][id];
      delete this.eventObj[name];
  }
  // 发布事件
  $emit(name, ...args) {
      const eventList = this.eventObj[name];
      if (!eventList) return -1;
      for (const event of eventList) {
          event && event(...args);
      }
      return 1;
  }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


# 2022-07-17

节流函数

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">1</div>
  </body>
  <script src="./js/Throttle.js"></script>
  <script>
    let event = (e) => {
      let i = e.target.innerHTML - 0;
      e.target.innerHTML = ++e.target.innerHTML;
      // console.log()
    };
    document
      .querySelector(".container")
      .addEventListener(
        "mousemove",
        throttle(event, 2000, { leading: false, trailing: true })
      );
  </script>
</html>
/**
 * 
 * @param { Function } func 
 * @param { Number } wait 
 * @param {
 *          禁止第一次执行时
 *          leading: false, 
 *          允许最后回调
 *          trailing: true
 *        } options 
 * @returns 
 */
function throttle (func, wait, options) {
  let timeout;
  let context;
  let args;
  // 上一次时间
  let previous = 0;
  if (!options) options = {};
  
  let leading = options.leading;
  let trailing = options.trailing;

  let throttled = function () {

    context = this;
    args = arguments;

    let now = new Date().getTime();
    
    // previous 为 0 (即第一次调用,且 禁止第一次执行时)
    if (!previous && leading === false) previous = now;
    
    // 计算 触发间隔 与 规定间隔时间差值
    let remaining = (wait + previous) - now;

    // 在 previous + wait 这段时间外又再次触发
    if (remaining <= 0) {
      
      // 清除最后回调定时器
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }

      // 更新本次时间
      previous = now;

      // 调用回调函数
      func.apply(context, args);

      // 垃圾回收
      if (!timeout) context = args = null;
      // 在 wait + previous 时间内触发,设置最后的回调函数
    } else if (!timeout && trailing !== false) {
      
      // 再隔 remain (差值) 设置最后一个定时器
      timeout = setTimeout(later, remaining)

      // 垃圾回收
      if (!timeout) context = arg = null;
    }
  };

  let later = function () {
    previous = leading === false ? 0 : new Date();
    timeout = null;
    func.apply(context, args);
  };
  return throttled;
}

在这里插入图片描述

在这里插入图片描述


# 2022-07-18

defineProperty 双向数据绑定

// 设置单一属性
function $setKeyResponse(obj, key, area) {
  let renderArea = document.querySelector(area)
  Object.defineProperty(obj, key, {
    get() {
      return this.value;
    },
    set(val) {
      // 视图层更新
      renderArea.innerText = val;

      // 数据层更新
      this.value = val;
    }
  })
}

// 设置所有属性
function $setFullResponse(obj) {
  Object.keys(obj).forEach(key => {
    Object.defineProperty(obj, key, {
      get() {
        return this.value
      },
      set(value) {
        // 根据 key 进行视图更新
        // .......
        // 数据层面更新
        this.value = value;
      }
    })
  })
}

注:

(1)只能对对象属性进行劫持,不能对整个对象进行劫持

(2)不能监听到对象属性的增加和删除

(3)数组的 push、pop、shift、unshift、splice、sort,reverse是无法触发 set 方法

在 vue 中之所以能够监听数组中 push、pop、shift、unshift、splice、sort,reverse 方法是因为 vue 重写了这些方法

Proxy 双向数据绑定

function $setKeyResponse(target, key) {
  return new Proxy(target, {
      get(target, prop) {
          return Reflect.get(target, prop)
      },
      set(target, prop, value) {
          // // 单一属性
          // if (Reflect.has(target, key)) {
          //     console.log("更新")
          // }
          Reflect.set(target, prop, value)
      },
      deleteProperty(target, prop) {
          console.log("删除属性", prop)
          Reflect.deleteProperty(target, prop)
          return true
      }
  })
}

注:

(1)Proxy 劫持的是对象,因此可以拦截到对象中所有属性的增加删除

(2)proxy 可以且不需要对数组的方法进行重载

<input type="text" />
<button>确定</button>
<div class="area"></div>
 <!-- <script src="./js/defineProperty.js"></script> -->
<script src="./js/proxy.js"></script>
<script>
    let obj = {};
    let inp = document.querySelector("input[type='text']")
    $setKeyResponse(obj, "message", ".area");
    inp.oninput = () => (obj.message = inp.value);
</script>

在这里插入图片描述


# 2022-07-19

获取url 请求参数

// 2022-07-19-1.js
function getParam(search) {
  let fullUrl = location.search;
  if (fullUrl.indexOf("?") == 0 && fullUrl.indexOf("=") > 1) {
      let obj = {};
      let arrsource = unescape(fullUrl).substring(1, fullUrl.length).split("&");
      arrsource.forEach(item => {
          let arr = item.split("=");
          obj[arr[0]] = arr[1];
      });
      return obj[search];
  }
}
console.log(getParam("classId"));
console.log(getParam("id"));
location.href = "http://127.0.0.1:5500/c.html?classId=123&examId=321"

寻找最值

function findMax(arr) {
    var len = arr.length;
    var max = arr[0]
    for (var i = 0; i < len; i++) {
        if (arr[i] > max) max = arr[i]
    }
    return max;
}

function findMin(arr) {
    var len = arr.length;
    var min = arr[0]
    for (var i = 0; i < len; i++) {
        if (arr[i] < min) min = arr[i]
    }
    return min;
}

var arr = [1, 2, 4, 3, 8, 3, 2, 6, 9]
console.log("max:", findMax(arr))
console.log("min:", findMin(arr))

在这里插入图片描述


# 2022-07-20

运算符及条件符

console.log("---------------------------------------");
// 左移
console.log("2 << 4:", 2 << 4);
// 右移
console.log("32 >> 4:", 32 >> 4);
console.log("---------------------------------------");

// & 与运算符
console.log("3 & 2 与运算符:", 3 & 2);
// 0b011 & 0b010 == 0b010 == 2
// | 或
console.log("3 | 2 与运算符:", 3 | 2);
// 0b011 & 0b010 == 0b011 == 3
console.log("---------------------------------------");

// | & 优先级,从左到右
console.log("0b100 & 0b101 | 0b110:", 0b100 & 0b101 | 0b110)
console.log("---------------------------------------");

// && 
console.log("true && 1:", true && 1);
console.log("false && 1:", false && 1);
console.log("---------------------------------------");

// || 
console.log("true || 1:", true || 1);
console.log("false || 1:", false || 1);
console.log("---------------------------------------");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkM2koxE-1671255563362)(笔记/2022-07-20.png)]

  • <<(左移):一个操作数进行左移运算的时候,结果就是等于操作数乘以2的n次方,n就是左移 的位数
  • >>(右移):一个操作数在做右移运算的时候,实际上就是等于该操作数除以2的n次方,n就是右移的位数
  • & 与运算符:全都为1,与后还是1,其他情况都为 0
  • | 或运算符:至少一个为1,或后还是1
  • 都存在 & | 时从左到右开始运算
  • a && b: a为假时,返回 a,反之为 b
  • a || b:a为真时,返回 a,反之为 b
  • &、| 优先级高于 &&、||

# 2022-07-21

虚拟DOM 转 真实 DOM

// 真正的渲染函数
function _render(vnode) {
  // 如果是数字类型转化为字符串
  if (typeof vnode === "number") {
    vnode = String(vnode);
  }
  // 字符串类型直接就是文本节点
  if (typeof vnode === "string") {
    return document.createTextNode(vnode);
  }
  // 普通DOM
  const dom = document.createElement(vnode.tag);
  if (vnode.attrs) {
    // 遍历属性
    Object.keys(vnode.attrs).forEach((key) => {
      const value = vnode.attrs[key];
      dom.setAttribute(key, value);
    });
  }
  // 子数组进行递归操作
  vnode.children.forEach((child) => dom.appendChild(_render(child)));
  return dom;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script src="./js/render.js"></script>
    <script>
      let dom = {
        tag: "DIV",
        attrs: {
          id: "app",
        },
        children: [
          {
            tag: "SPAN",
            children: [{ tag: "A", children: [] }],
          },
          {
            tag: "SPAN",
            children: [
              { tag: "A", children: [] },
              { tag: "A", children: [] },
            ],
          },
        ],
      };
      console.log(_render(dom))
    </script>
  </body>
</html>

# 2022-07-22

冒泡排序

基本思想:循环遍历,每次从前往后把大元素往后调

function BubbleSort (arr) {
  var len = arr.length;
  var temp;
  for (var i = 0; i < len; i++) {
      for (var j = 0; j < len - 1; j++) {
          if (arr[i] < arr[j]) {
              temp = arr[i];
              arr[i] = arr[j];
              arr[j] = temp;
          }
      }
  }
}

let arr = [];
for (let i = 0; i < 1000; i++) {
  let num = Math.floor(Math.random()* (1000 - 1)) + 1;
  arr.push(num);
}

console.time()
BubbleSort(arr);
console.timeEnd();
console.log(arr);

在这里插入图片描述

【算法分析】

时间复杂度 O(n^2)

空间复杂度O(1)

【特点】

  • 稳定排序
  • 可用于链式存储结构
  • 移动记录次数较多,算法平均时间比直接插入排序差,当初始记录无序,n较大时,此算法不宜采用

补充:可提前结束

function BubbleSort(arr) {
    let len = arr.length;
    let flag = 1;
    while (len > 0 && flag == 1) {
        flag = 0;
        for (let j = 1; j <= m; j++) {
            if (arr[j] > arr[j+1]) {
                flag = 1;
                let temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

# 2022-07-23

快速排序

基本思想

  • 找到数组中最中间的数值,以该数值为基点,大于该值则放在右侧,反之,左侧。
  • 然后利用递归的思想再将左序列当成一个完整的序列再进行排序。
  • 同样把序列的右侧也当成一个完整的序列进行排序。
  • 直到数组长度 <= 1,返回该数组。

方法一:借助俩数组空间

let arr = [1, 5, 3, 7, 6, 8, 12, 0];
function quick(arr) {
    let len = arr.length;

    // 长度为 1
    if (len <= 1) return arr;

    // 取中间值
    let contentValue = arr.splice(Math.floor(len / 2), 1)[0];

    // console.log(contentValue) 6
    // console.log(arr) [1, 5, 3, 7, 8, 12, 0]

    let leftArr = [];
    let rightArr = [];
    for (let i = 0; i < len - 1; i++) {
        let item = arr[i];
        item > contentValue ? rightArr.push(item) : leftArr.push(item)
    }

    return quick(leftArr).concat(contentValue, quick(rightArr))
}
console.log(quick(arr));

在这里插入图片描述


方法二:Lomuto partition scheme

思路:在第一方法的基础之上,利用分区的方式,不借助数组空间

/**
 * 
 * @param { Array } arr 
 * @param { Number } left // 左数组起始下标 
 * @param { Number } right  // 右数组起始下标
 */
let i = 0;
function quicksort(arr, left, right) {
  let partitonIndex;

  left = typeof left !== 'number' ? 0 : left;
  right = typeof right !== 'number' ? arr.length - 1 : right;

  if (left < right) {
    partitonIndex = partition(arr, left, right);
    // 左侧快排
    quicksort(arr, left, partitonIndex - 1);
    // 右侧快排
    quicksort(arr, partitonIndex + 1, right);
  }
  console.log(`${++i}遍遍历结果为${arr.toString()}`);
  return arr;
}
// 分区
function partition(arr, left, right) {
  // 基准点下标
  let pivot = left;
  // 数组第二位开始比较
  let index = pivot + 1;
  for (let i = index; i <= right; i++) {
    // 小于基准点值
    if (arr[i] < arr[pivot]) {
      swap(arr, i, index);
      index++;
    }
  }
  swap(arr, pivot, index - 1);
  return index - 1;
}
// 值交换
function swap(arr, i, j) {
  let temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}
let arr = [1, 2, 66, 44, 33, 3, 22, 13]
quicksort(arr)
console.log(arr)

在这里插入图片描述

每次排序取最左边的值为基准值,每次排序结束后,基准值的左侧一定小于基准值。


方法三:Hoare partition scheme

思路:以挖萝卜填坑为例子实现该算法

规则:

  • 首先,一连串待排序的数值指的是该排萝卜的大小。

  • 两个工人A、B分别站在并排萝卜的最左侧和最右侧

  • 确定填坑的判断依据

    • 以挖出最左边的萝卜为基准值。
    • A 为 B 填坑的标准是 挖到的萝卜必须比基准值大,才可为 B 填坑
    • B 为 A 填坑,则比基准值小。
  • 两工人挖萝卜的方向,及其萝卜是否符合规则。

    • A :从左到右,并且该萝卜必须在 B 的左侧
    • B:从右到左,并且该萝卜必须在 A 的右侧
  • 谁先开始:

    • 一方坑为空时,另外一方先开始为其填坑。
    • 根据前面几点要求,此时 A 所站位置为坑,B为其填坑。
  • 什么时候结束:

    俩个工人相遇,则结束该次填坑。

    • 并且相遇位置必定为坑。
    • 把一开始挖出来的萝卜给填到该坑上。可以看到以该位置为基准,左侧都小于该值,右侧都大于该值。
    • 到这里,需要以相遇位置,将其分割成左侧和右侧萝卜,再分别完成两侧的萝卜游戏。
    • 已此类推,直到开始填坑前判断起始位大于等于结束位,则说明萝卜已排好序。

游戏开始:

function quicksort(arr, left, right) {
    let len = arr.length;

    // 起始位
    left = typeof left !== 'number' ? 0 : left;
    // 结束位
    right = typeof right !== 'number' ? len - 1 : right; 
    
    // 两者相遇
    if (left >= right) return

    // 挖出最左边萝卜
    let value = arr[left] 

    // 工人 A 所站位置
    let A = left;
    // 工人 B 所站位置
    let B = right;

    // 两人没有相遇
    while (A < B) {
       // 此时 工人 A 位置是一个空坑

       // B从右往左找比 最左边(value)小的萝卜,并且其位置正在工人 A 的右侧
       while (B > A && arr[B] >= value) {
           B--;
       }
       // B 找到啦,把该位置的萝卜挖个 工人 A 进行填坑
       arr[A] = arr[B];
       // 此时 工人 B 位置是一个空坑

       // A从左往右找比 最左边(value)大的萝卜,并且其位置正在工人 B 的左侧
       while (A < B && arr[A] <= value) {
           A++;
       }
       // A 找到啦 该位置的萝卜挖个 工人 B 进行填坑
       arr[B] = arr[A];
       // 此时 工人 A 位置是一个空坑

       // 如果俩工人没有相遇,则再次为对方填坑
    }
    /*
      该次填坑结束,此时 工人A、工人B(A == B)相遇,并且该位置为空,将一开始挖出来的萝卜   (value)放到该位置上
      
      此时形成的结果是:相遇位置的左侧都小于 value,右侧都大于 value
    */
    arr[A] = value; 

    // 在相遇位置作为分隔点,将其分割成俩个数组,在进行递归

    // 左侧萝卜
    quicksort(arr, left, A);
    // 右侧萝卜
    quicksort(arr, A + 1, right);
}
let arr1 = [];
let arr2 = [];

for (let i = 0; i < 300000; i++) {
    let num = Math.floor(Math.random() * (10000 - 1) + 1);
    arr1.push(num)
    arr2.push(num)
}
console.time()
quicksort(arr1)
console.timeEnd()
console.log(arr1)

console.log("----------------")

console.time()
arr2.sort((a, b) => a - b)
console.timeEnd()
console.log(arr2)

在这里插入图片描述


三种方法总结

  • 三种方法都是不稳定排序,但与冒泡排序相比较最大的特点是快,并且当数量较大时,在平均情况下快速排序是所有排序方法中最快的一种
  • 时间复杂度
    • 最坏:O(n^2) 指的是序列已经排好序
    • 最好:O(nlogn)
    • 平均:O(nlogn)
  • 除了方法一外,其他两种方法属于原地排序
  • 方法一:以牺牲空间,换取时间上的优势。
  • 方法二和三:则没有借助其他存储空间的基础上实现了该算法,并且两者都要优于方法一。
  • 性能方面:方法一 < 方法二 < 方法三

# 2022-07-24

直接插入排序

思想:

  • 从序列第一个元素开始,该元素可以认为已经被排序。

  • 取出下一个元素,设为待插入元素,在已经排序的元素序列中从后向前扫描,如果该元素(已排序)大于待插入元素,将该元素移到下一位置。

  • 重复步骤2,直到找到已排序的元素小于或者等于待排序元素的位置,插入元素。

  • 重复2,3步骤,完成排序。

在这里插入图片描述

let instertSort = arr => {
    let temp = 0;
    for (let i = 1; i < arr.length; i++) {
        temp = arr[i];

        for (let j = i - 1; j >= 0; j--) {
            if (temp < arr[j]) {
                arr[j + 1] = arr[j];
                arr[j] = temp;
            } else {
                break
            }
        }
    }
}

let arr = [10, 2, 11, 3, 5, 4, 11, 23, 12, 10]
instertSort(arr);
console.log(arr);

在这里插入图片描述

【算法分析】

  • 时间复杂度 O(n^2)
  • 空间复杂度是O(1)

【算法特点】

  • 稳定排序
  • 适用于链表结构,在单链表结构上无需移动记录,只需修改相应的指针
  • 更适合于初始记录基本有序(正序)的情况,当初始化记录无序,n较大时,此算法时间复杂度较高,不宜采用。

希尔排序

思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序

在这里插入图片描述

let shellSort = arr => {
    let len = arr.length;
    let temp;
    // 间隔
    let gap = 1;

    // 动态定义间隔序列 
    while (gap < len / 3) {
       gap = gap * 3 + 1;
    }

    for (gap; gap > 0; gap = Math.floor(gap / 3)) {
       
        for (let i = gap; i < len; i++) {
            
            
            temp = arr[i];
            
            let j = i - gap;
           

            for(; j >= 0 &&  temp < arr[j]; j -= gap) {
                arr[j + gap] = arr[j];
            }

            arr[j + gap] = temp;
        }
    }

}
let arr = [10, 2, 11, 3, 5, 4, 14, 22, 19, 18, 25, 23, 12, 16, 15]
shellSort(arr)
console.log(arr)

【算法分析】

  • 不稳定 原地排序
  • 最佳情况:T(n) = O(n logn)。 最差情况:T(n) = O(n (log(n))2)。 平均情况:T(n) = 取决于间隙序列
  • 空间复杂度: O(1)

【算法特点】

  • 记录跳跃式地移动导致排序方法不是很稳定
  • 只能用于顺序结构,不能用于链式结构
  • 记录总的比较次数和移动次数都比直接插入排序要少,n越大时,效果越明显

# 2022-07-25

简单选择排序

思路:每次从待排序中的序列中找到一个最小值,并将该值从左往右依次插入到序列中

在这里插入图片描述

// 简单选择排序
let simpleSelectSort = arr => {
  let len = arr.length;
  for (i = 0; i < len - 1; i++) {
    // 每次已第一个为最小值
    let min = i;

    // 从第 i + 1 开始找最小值
    for (let j = i + 1; j < len; j++) {
       if (arr[j] < arr[min]) min = j;
    }

    // 找到最小值
    if (min != i) {
       let temp = arr[i];
       arr[i] = arr[min];
       arr[min] = temp;
    }
    console.log(`${i}次排序 ${arr.toString()}`);
  }
}
let arr = [10, 2, 11, 3, 5, 4, 11, 23, 12, 10]
simpleSelectSort(arr);
console.log(arr)

在这里插入图片描述

【算法分析】

  • 简单排序过程中,所需进行记录移动的次数较少。最好情况(正序):不移动;最坏情况(逆序):移动3(n-1)次
  • 不管什么情况,时间复杂度都为 O(n^2)
  • 空间复杂度:O(1)

【算法特点】

  • 稳定排序
  • 可以用于链表存储结构

# 2022-07-26

堆排序

const heapSort = array => {
    // 初始化大顶堆
    for (let i = Math.floor(array.length / 2 - 1); i >= 0; i--) {
        heapify(array, i, array.length)
    }

    // 排序,每一次 for 循环找出一个当前最大值,数组长度减一
    for (let i = Math.floor(array.length - 1); i > 0; i--) {
        swap(array, 0, i);
        heapify(array, 0, i);
    }

    return array;
}

function swap (array, i, j) {
  let temp = array[i];
  array[i] = array[j];
  array[j] = temp;
}

function heapify(array, i , length) {
   // 当前父节点
   let temp = array[i];
   // j < length 的目的是堆结点 i 以下的结点全部做顺序调整
   for (let j = 2 * i + 1; j < length; j = 2 * j + 1) {
      // 将 array[i] 取出,整个过程相当于找到array[i]应处于的位置
      if (j + 1 < length && array[j] < array[j + 1]) {
        // 找到 两个孩子中较大的一个,再与父结点比较
        j++; 
      }
      if (temp < array[j]) {
        swap(array, i, j);
        i = j; // 交换后, temp 的下标变为j
      } else {
        break;
      }
   }
}
const array = [4, 6, 8, 5, 9, 1, 2, 5, 3, 2];
const newArr = heapSort(array);
console.log(newArr);

在这里插入图片描述


# 2022-07-27

归并排序

let mergeSort = arr => {
    let len = arr.length;
    
    if (len < 2) return arr;

    let middle = Math.floor(len / 2);
    
    let left = arr.slice(0, middle);
    let right = arr.slice(middle);

    return merge(mergeSort(left), mergeSort(right))
}

let merge = (left, right) => {
    let result = [];

    while (left.length && right.length) {
        if (left[0] <= right [0]) {
            result.push(left.shift())
        } else {
            result.push(right.shift())
        }
    }
    while(left.length) result.push(left.shift());
    while(right.length) result.push(right.shift());
  
    return result;
}
// 测试
const arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48];
console.time('归并排序耗时');
console.log('arr :', mergeSort(arr));
console.timeEnd('归并排序耗时');

在这里插入图片描述


# 2022-07-28

Array.prototype.filter()

Array.prototype._filter = function(callback, thisArg) {
  if (this == undefined) throw new TypeError('this is null or not undefined');
  if (typeof callback !== 'function') throw new TypeError(callback + 'is not a function');
  
  const filterArr = [];
  const array = Object(this);
  // 保证len为正整数
  const len = O.length >>> 0;
    
  for (let i = 0; i < len; i++) {
    // 检查i是否在 array 的属性(会检查原型链)
    if (i in array) {
      // 回调函数调用传参
      if (callback.call(thisArg, O[i], i, array)) {
        filterArr.push(O[i]);
      }
    }
  }
  return filterArr;
}
let arr = [1, 4, 4, 5, 2, 6, 10, 5, 6, 4, 6]
arr._filter((item, i) => item > 4)
console.log(arr)

在这里插入图片描述

Array.prototype.map()

Array.prototype._map = function(callback, thisArg) {
  if (this == undefined) throw new TypeError('this is null or not defined');
  if (typeof callback !== 'function') throw new TypeError(callback + ' is not a function');
  
  const res = [];
 
  const array = Object(this);
  // 保证len为正整数
  const len = array.length >>> 0;

  for (let i = 0; i < len; i++) {
    if (i in array) {
      // 调用回调函数并传入新数组
      res[i] = callback.call(thisArg, array[i], i, this);
    }
  }
  return res;
}
let arr = [1, 4, 4, 5, 2, 6, 10, 5, 6, 4, 6]
let mapArr = arr._map((item, i) => item * 2)
console.log(mapArr)

在这里插入图片描述


# 2022-07-29

Array.prototype._forEach()

Array.prototype._forEach = function(callback, thisArg) {
  if (this == null) throw new TypeError('this is null or not defined');
  if (typeof callback !== "function")  throw new TypeError(callback + ' is not a function');
  
  const arr = Object(this);
  const len = arr.length >>> 0;
  for (let i = 0; i < len; i++) {
    callback.call(thisArg, arr[i], i, arr);
  }  
}

let arr = [
  {
    name: "小明",
    age: 12
  },
  {
    name: "小红",
    age: 12
  }
]
arr._forEach(item => {
  console.log(`${item.name} - ${item.age}`)
})

在这里插入图片描述


# 2022-07-30

Array.prototype.reduce()

Array.prototype.reduce = function(callback, initialValue) {
  if (this == undefined) throw new TypeError('this is null or not defined');
  if (typeof callback !== 'function') throw new TypeError(callbackfn + ' is not a function');
  
  const arr = Object(this);
  const len = arr.length >>> 0;
  
  let accumulator = initialValue;
  let k = 0;
  // 如果第二个参数为undefined的情况下
  // 则数组的第一个有效值作为累加器的初始值
  if (accumulator === undefined) {
    while (k < len && !(k in O)) {
      k++;
    }
    // 如果超出数组界限还没有找到累加器的初始值,则TypeError
    if (k >= len) {
      throw new TypeError('Reduce of empty array with no initial value');
    }
    accumulator = O[k++];
  }
  while (k < len) {
    if (k in O) {
      accumulator = callback.call(undefined, accumulator, O[k], k, O);
    }
    k++;
  }
  return accumulator;
}

# 2022-07-31

并发数控制

class Scheduler {
  constructor() {
    this.queue = [];
    this.maxCount = 2;
    this.runCounts = 0;
  }
  add(promiseCreator) {
    this.queue.push(promiseCreator);
  }
  taskStart() {
    for (let i = 0; i < this.maxCount; i++) {
      this.request();
    }
  }
  request() {
    if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {
      return;
    }
    this.runCounts++;

    this.queue.shift()().then(() => {
      this.runCounts--;
      this.request();
    });
  }
}
   
const timeout = time => new Promise(resolve => {
  setTimeout(resolve, time);
})
  
const scheduler = new Scheduler();
  
const addTask = (time,order) => {
  scheduler.add(() => timeout(time).then(()=>console.log(order)))
}
  
  
addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
scheduler.taskStart()
// 2
// 3
// 1
// 4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机(Android)刷NetHunter安装指南,无需ssh执行kali命令, NetHunter支持的无线网卡列表!

一、安装NetHunter 前提&#xff1a;确保手机已经root&#xff0c;已装上magisk。如果没有root&#xff0c;可用尝试magisk root 后执行此文 1、下载Nethunter&#xff1a;Get Kali | Kali Linux 然后push 到sdcard 里&#xff0c; 2、打开magisk&#xff0c;选择刚刚下好的…

krpt.dll丢失怎么安装?怎么修复快一点

krpt.dll丢失怎么安装&#xff1f;其实你只要记住一点&#xff0c;只要是dll文件丢失&#xff0c;那么就不外乎那几种修复方法&#xff0c;自己下载丢失的文件安装&#xff0c;或者使用dll修复工具&#xff0c;这些方法都是可以修复的。下面我们详细的说一说。 目录 一.krpt.…

性能优化-内存泄漏、内存溢出、cpu占用高、死锁、栈溢出、FullGC频繁检测手段-总结与分享

介绍 什么是内存泄漏 含义&#xff1a;内层泄露是程序中己动态分配的堆内存由于某种原因程序未释放或无法释放&#xff0c;造成系统内存的浪费。&#xff08;换言之&#xff0c;GC回收不了这些不再被使用的对象&#xff0c;这些对象的生命周期太长&#xff09; 危害&#xff…

Linux学习03-Linux基础命令1

1 开始执行命令 command [-options] parameter1 parameter2 一行命令中第一个输入的部分绝对是命令或者可执行文件。 例如 ls命令列出目录的文件&#xff0c;需要列出隐藏文件则加 -al。 ls -al ls ls -a -l 2 基础命令操作 显示日期与时间的命令&#xff1a;date 显示日…

Ubuntu22.04系统中二进制包安装公有云k8s

目录公有云版k8s的架构是怎样的公有云中创建k8s实例的过程如下二进制法创建k8s的一般过程Kubernetes的重要性check nodes每台服务器执行基线配置CA rootetcd HA cluster根据CA根证书创建etcd的专有CA证书将etcd注册成为systemd服务配置各master节点的etcd.confansible配置各个m…

东北大学2023分布式操作系统考试重点

Note&#xff1a;以下10个点为老师画的重点 1.分布式系统目标 第一章 分布式系统概论&#xff0c;第二节 2.RPC过程 第四章 分布式通信管理&#xff0c; 第二节 客户过程以普通方式调用相应的客户存根客户存根建立消息并激活内核陷阱内核将消息发送到远程内核远程内核将消息…

计算机毕设Python+Vue写字楼物业管理系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

C++ Reference: Standard C++ Library reference: Containers: map: map: operator[]

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/operator[]/ 公有成员函数 <map> std::map::operator[] C98 mapped_type& operator[] (const key_type& k); C11 mapped_type& operator[] (const key_type& k); mapped_type& …

SQL基础——数据更新

数据更新前言思维导图数据的插入&#xff08;INSERT语句的使用方法&#xff09;什么是INSERTINSERT语句的基本语法语法4.1 INSERT语句代码示例4.2 创建 ProductIns表的CREATE TABLE语句代码示例4.3 向表中插入一行数据代码示例4.4 INSERT插入多行数据列清单的省略代码示例4.5 省…

chatGPT的49种应用场景,及各开发语言对接chatGPT参考指南

前沿 可能有人在问我&#xff0c;勇哥为什么chatGPT都被微信下架了&#xff0c;你还要写相关的chatGPT的文章呢&#xff1f;其实我们先不论微信下架的原因&#xff0c;单说chatGPT的达芬奇模型给勇哥带来的科技感早就超越了一切&#xff0c;所以勇哥依旧决定连续熬两个夜为大家…

【与达梦同行】达梦驱动图谱

达梦驱动图谱 摘要 达梦提供了大部分主流开发语言的驱动接口&#xff0c;在我用使用过的国产数据库中对客户端驱动的支持应该算是非常不错的。本文主要介绍达梦的驱动开发&#xff0c;通过实际操作&#xff0c;从环境搭建到实践验证&#xff0c;介绍了达梦各种语言驱动的详细使…

博途S7-1500T 使用工艺对象驱动液压轴(含SimaHydTO库)

利用工艺对象控制液压轴位置含PLC控制和仿真程序文档资料下载地址如下: https://support.industry.siemens.com/cs/document/109756217/simatic-s7-1500(t)-lsimahydto-for-hydraulic-applications-and-hydraulic-presses?dti=0&dl=en&lc=zh-CNhttps://support.indu…

圣诞树-python绘制雪夜圣诞树并封装为小程序

绘制雪夜圣诞树并封装为小程序 使用turtle绘制一颗雪夜圣诞树&#xff0c;然后封装成exe小程序送给你的朋友吧&#xff01; PS&#xff1a;只能在windows运行。 转载注明本文链接和作者 先看效果图&#xff1a; 绘制雪夜圣诞树 由于代码有三百多行&#xff0c;我放在下面的两…

一文彻底搞懂cookie、session、token

1.Cookie Cookie是客户端保存用户信息的一种机制&#xff0c;用来记录用户的一些信息&#xff0c;实际上Cookie是服务器在本地机器上存储的一小段文本&#xff0c;并随着每次请求发送到服务器。 Cookie技术通过请求和响应报文中写入Cookie信息来控制客户端的状态。 Cookie会…

28.项目搭建网关

项目搭建网关 一、项目架构 二、创建模块&#xff0c;引入依赖&#xff0c;创建启动类&#xff0c;添加application.yml配置文件 2.1依赖 <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-…

【AI with ML】第 9 章 :了解序列和时间序列数据

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

【linux】linux环境变量初始化与对应文件的生效顺序

1.认识环境变量&#xff08;PATH) 环境变量&#xff08;PATH&#xff09;是一个列表&#xff0c;里面是有序的一些程序的地址&#xff08;一般是xxx/bin&#xff09;&#xff0c;添加环境变量后&#xff0c;系统在任何目录输入命令&#xff0c;都可以识别命令并执行命令对应程…

一个工程师的自我修养!

Datawhale干货 Tw93&#xff0c;前端工程师&#xff0c;Datawhale邀约作者对计算机科学的掌握程度&#xff0c;决定了一个计算机行业从业者能走多远。吴军博士在《浪潮之巅&#xff08;第四版&#xff09;》对工程师做了五个级别的划分&#xff1a;一级&#xff1a;能够开创一个…

询问ChatGPT来了解什么是边缘计算,有哪些特点,有哪些关键技术,和云计算的关系是什么?

什么是云计算 云计算是一种计算架构&#xff0c;它使用互联网作为基础设施&#xff0c;允许用户通过网络访问共享的计算资源&#xff0c;而不需要拥有专门的本地计算机硬件和软件。云计算提供了计算能力、存储空间、应用程序和服务等&#xff0c;并使用计费模型收取使用费用。…

springboot基于ssm框架实现的家具商城管理系统

一、项目简介 本项目是一套基于springboot框架实现的家具商城管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&#…