为了账号安全,请及时绑定邮箱和手机立即绑定

学习JavaScript数据结构和算法(第二版) 读后感

标签:
JavaScript

总体概述

  • 本书是由[巴西] 格罗纳(Loiane Groner)[著作],全书总共238页;

  • 本书从介绍javascript语言入手,然后分别介绍了数组(列表)、栈、队列、链表等顺序数据结构,然后依次介绍了集合、字典、散列表、树和图等非顺序结构,最后介绍了排序和搜索算法,以及算法复杂度;

  • 接下来,我将从 (简述基础部分) 和  (详述 树、排序及其复杂度) 两方面进行分享,有不足的欢迎讨论:

一、简述基础部分

  1. 数组
    1)数组其实就是内存里连续的一块地址,当删除某一个块时,其他内容向前移动,我理解为数组塌陷;
    2)数组中常用的方法:增、删、改、查、克隆、遍历等


  2. 1)后进先出,例如:坐电梯,用数组表示 push / pop

  3. 队列
    1)先进先出,例如:排队上厕所,用数组表示 push/shift

  4. 链表
    1)链表其实是内存里不连续的地址
    2)单项链表:一个节点有两个地址(一个放内容,一个放next指针)
    3)双向链表:一个节点有三个地址(一个放内容,一个放next指针,一个放pre指针)

  5. 集合
    1)一个对象,里面内容无序且唯一;可以求并集、差集、子集;

  6. 字典和散列表
    1)查找数组内容,需要循环,浪费时间,最好有找到key,立马找到value的效果
    2)字典也叫映射,是通过散列算法来实现的,key是唯一的,然后通过key就可以找到value,需要得到一种key不冲突且查得快;有两种方式计算key:分离连接、线性探测

二、详述-二叉树

  • 增加和遍历
    增加思路:
    1、先判断是否有根节点root,如果没有,直接赋值新节点;
    2、如果有了,判断左子树是否为空,不为空时逐层递归,直至找到进行赋值;
    3、同理判断右子树
    遍历思路:
    1、中序:左中右,以左分支的最小值为起点遍历


    webp


    2、先序:中左右,以root根节点为起始点遍历


    webp

    image.png


    3、后序:左右中,以左分支最小值为起点遍历

    webp

    image.png

;(function () {  var root = null
  class Node { // 节点类
    constructor (key) {      this.key = key      this.l = null
      this.r = null
    }
  }  class BinarySearchTree { // 二叉树类
    constructor () {}
    insert (key) { // 插入节点
      let newNode = new Node(key)      if (root === null) { // 没有根节点情况
        root = newNode
      } else { // 有根节点,进行节点比较
        this.insertNode(root, newNode)
      }
    }
    insertNode (node, newNode) {      if (newNode.key < node.key) {//新节点小于node节点
        if (node.l === null) {
          node.l = newNode
        } else {          this.insertNode(node.l, newNode) //跟node.l递归比较
        }
      } else {//新节点大于node节点
        if (node.r === null) {
          node.r = newNode
        } else {          this.insertNode(node.r, newNode) // 跟node.r字节点递归比较
        }
      }
    }
    inOrderTraverse (callback) { // 遍历节点
      this.inOrderTraverseNode(root, callback)
    }
    inOrderTraverseNode (node, callback) { // 中序遍历:左中右
      if (node !== null) {        this.inOrderTraverseNode(node.l, callback)
        callback(node.key)        this.inOrderTraverseNode(node.r, callback)
      }
    }
    preOrderTraverseNode (node, callback) { // 先序遍历:中左右
      if (node !== null) {
        callback(node.key)        this.inOrderTraverseNode(node.l, callback)        this.inOrderTraverseNode(node.r, callback)
      }
    }
    postOrderTraverseNode (node, callback) { // 先序遍历:左右中
      if (node !== null) {        this.inOrderTraverseNode(node.l, callback)        this.inOrderTraverseNode(node.r, callback)
        callback(node.key)
      }
    }
  }// 打印输出,进行代码测试
  function printNode (value) {    console.log(value)
  }  let tree = new BinarySearchTree()
  tree.insert(11)
  tree.insert(7)
  tree.insert(15)
  tree.insert(5)
  tree.insert(3)
  tree.insert(9)
  tree.insert(10)
  tree.insert(13)
  tree.insert(12)

  tree.inOrderTraverse(printNode)
})()
  • 二分查找法
    思路:
    1、先将数组进行排序后,设置必要的两个指针,low和high
    2、当low<high时,取中间索引min,并求出中间值element
    3、当element<item,让low指针左移;反之,high指针右移;若两者都不是,直接返回min(即找到的元素的索引)
    注意:
    1、因为不知道要比较和移动多少次,所以使用while循环
    2、min值是不断变化的(它随low和high指针的变动而变动Math.floor((low + high) / 2))

this.binarySearch = function(item){    this.quickSort();  // 先将数组进行排序,一会会介绍排序的多种思路
    var low = 0,                
      high = array.length - 1,  //low,height为指针
      mid, element;    while (low <= high){ 
      mid = Math.floor((low + high) / 2); 
     element = array[mid];    if (element < item) {
      low = mid + 1;
    } else if (element > item) {
      high = mid - 1;
    } else {      return mid;
    }     return -1; 
};
  • AVL平衡二叉树
    整个实现过程通过在一棵平衡二叉树中依次插入元素,若出现不平衡,则要根据新插入的节点与最低不平衡节点的位置关系进行响应的调整;分为:
    1、LL型:向右单旋转


    webp

    image.png


    2、RR型:向左单旋转


    webp

    image.png


    3、LR型:向右的双旋转

    webp

    image.png


    4、RL型:向左的双旋转

    webp

    image.png

三、详述-排序

  • 冒泡排序:

function  bubbleSort(arr){  var length = array.length;  for (var i=0; i<length; i++){ //外循环代表轮数
    for (var j=0; j<length-1-i; j++ ){ //内循环代表比较次数
      if (array[j] > array[j+1]){//拿当前项跟它的后一项进行比较
        [array[j] , array[j+1]] = [array[j+1], array[j]]
      }
    }
  }
}
  • 选择排序
    思路:用当前项跟他后面每一项进行对比,如果小了,就交换位置

function selectSort (arr) {  for (var i = 0; i < arr.length; i++) {    let minIndex = i    for (var j = i; j < arr.length; j++) {      if (arr[minIndex] > arr[j]) {
        minIndex = j
      }
    }    if (minIndex !== i) { 
      [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
    }
  }  return arr
}
  • 插入排序
    思路:
    1、左数组随机取出一张
    2、拿右数组每一张跟左数组从后往前的比较,比他小,就继续往前比较,比他大,就插入到当前项的下一项的前面

function insertSort (arr) {  var left = arr.splice(0, 1) // 左数组
  for (var i = 0; i < arr.length; i++) { // 右数组每一项跟左数组每一项从后往前进行比较
    var cur = arr[i]    for (var j = left.length - 1; j >= 0;) {      if (cur < left[j]) {
        j--        if (j === -1) {
          left.unshift(cur)
        }
      }else {
        left.splice(j + 1, 0 , cur)        break
      }
    }
  }  return left
}
  • 归并排序
    思路:先拆后合

function mergeSortRec (arr) {  var len = arr.length  if (len === 1) {    return arr
  }  var mid = Math.floor(len / 2),
    left = arr.slice(0, mid),
    right = arr.slice(mid, len)  return merge(mergeSortRec(left), mergeSortRec(right))
}function merge (left, right) {  var result = [],
    il = 0,
    ir = 0
  while(il < left.length && ir < right.length){    if (left[il] < right[ir]) {
      result.push(left[il++])
    }else {
      result.push(right[ir++])
    }
  }  while(il < left.length){
    result.push(left[il++])
  }  while (ir < right.length) {
    result.push(right[ir++])
  }  return result
}
  • 快速排序
    思路:
    1、通过中间位置mid,找到中间值midVal
    2、遍历数组每一项跟midVal比较,比他小的push到left数组,反之,push到right数组
    3、返回 left.concat([midVal], right) 但是因left和right数组未必能拼接好,我们还需要对他进行相同思路的拆分,所以,进行递归处理

function quickSort (arr) {  if (arr.length <= 1) {    return arr
  }  var mid = Math.floor(arr.length / 2)  var midVal = arr.splice(mid, 1)[0]  var left = []  var right = []  for (var i = 0; i < arr.length; i++) {    var cur = arr[i]    if (cur < midVal) {
      left.push(cur)
    }else {
      right.push(cur)
    }
  }  return quickSort(left).concat([midVal], quickSort(right))
}
  • 以下列出常用的排序算法的时间复杂度和空间复杂度

排序法最差时间平均时间复杂度稳定度空间复杂度
冒泡排序O(n^2)O(n^2)稳定O(1)
选择排序O(n^2)O(n^2)不稳定O(1)
插入排序O(n^2)O(n^2)不稳定O(1)
归并排序O(nlog2n)O(nlog2n)稳定O(1)
快速排序O(n^2)O(n*log2n)稳定O(log2n)~O(n)



作者:张蕾_
链接:https://www.jianshu.com/p/9c5ef91192a8


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消