#

栈的
// function Stack(){//version 1
//     this.stackArr=[];
//     this.push=(item)=>{
//         this.stackArr.splice(0,0,item);
//     }
//     this.pop=()=>{
//         this.stackArr.splice(0,1);
//     }
//     this.peek=()=>{
//         return this.stackArr[this.stackArr.length-1];
//     }
//     this.isEmpty=()=>{
//         return this.stackArr.length<=0;
//     }
// }
function Stack(){ //version 2
    const _item=Symbol("stack");
    this.count=0;
    this[_item]={};
    this.push=item=>{
        this.count++;
        this[_item][this.count]=item;
    }

    this.pop=()=>{
        const res=this[_item][this.count];
        delete this[_item][this.count--];
        return res;
    }
    this.peek=()=>{
        return this[_item][this.count];
    }
    this.isEmpty=()=>{
        return this.count===0;
    }
    this.toString=()=>{
        let res='';
        for(let i =this.count;i>=1;i--){
           res+=this[_item][i];
        }
        return res;
    }

}
// var stack=new Stack();//测试代码
// stack.push(1);
// stack.push(2);
// stack.push(3);
// stack.push(4);
// stack.push(5);
// console.log('删除最后一个',stack.pop());
// console.log("最后一个值:",stack.peek());
// console.log("toString",stack.toString());
// console.log(stack.isEmpty());
// var  sym=Object.getOwnPropertySymbols(stack);

# 队列

# 链表

function LinkedList() {
    this.count = 0;
    this.head = undefined;
    this.remove=(element)=>{
        const index=this.indexOf(element);
        this.count--;
        this.removeAt(index);
    }
    this.indexOf=(element)=>{
        if(!element||!this.head ){
            return;
        }else{
            let current=this.head;
            for(let i =0;i<this.count;i++){
                if(element===current.element.element){
                    return i;
                }
                current=current.next;
            }
        }
    }
    this.insert=(element,index=0)=>{
        if(!element||!this.head ||index < 0 || index > this.coun){
            return;
        }
        let current=this.head,prev;
        for(let i =0 ; i<index; i++){
            prev=current;   
            current=current.next;
        }
        prev.next=element;
        element.next=current;
        this.count++;
        return this.head;
    }
    this.getElementAt = (index)=>{//获取下标索引的链表节点
         if (!this.head || index < 0 || index > this.count) {
            return;
        }else{
            let content,current=this.head;
            for(let i=0;i<index;i++){
                content=current;
                current=current.next;
            }   
            return content
        }
    }
    this.removeAt = (index)=>{
        //移除某个节点
        if (!this.head || index < 0 || index > this.count) {
            return;
        }
        this.count--;
        if (index === 0) {
            this.head = this.head.next;
        } else {
            let current = this.head, prev;
            for (let i = 1; i <= index; i++) {
                prev = current;
                //拿到上一次的指针引用
                current = current.next;
                //取到本次的node
            }
            prev.next = current.next;
            //遍历完后说明已经走到了需要移除的索引下标位置,跳过一个node节点即可
        }
        return this.head;
    }
    this.push = (element)=>{
        const node = new Node(element);
        let current;
        this.count = 1;
        //初次push时
        if (!this.head) {
            //没有头指针指向第一个节点
            this.head = node;
        } else {
            current = this.head;
            while (current.next) {
                this.count++;
                current = current.next;
            }
            this.count++;
            current.next = node;
        }

    }
}
function Node(element) {
    this.element = element;
    this.next = undefined;
}
var linkedList = new LinkedList();
linkedList.push(new Node("Node1"))
linkedList.push(new Node("Node2"))
linkedList.push(new Node("Node3"))
linkedList.push(new Node("Node4"))
linkedList.push(new Node("Node5"))
// linkedList.getElementAt(3);
// linkedList.remove('Node5');
// linkedList.indexOf('Node3');
// linkedList.removeAt(2);
// linkedList.insert(new Node('Node6'),2);

# 双向链表


function DoubleLinkedList(){
    this.count=0;
    this.head=undefined;
    this.getElementAt=(index)=>{
        if(index<0||index>this.count){return};
        let current=this.head;
        for(let i =1;i<this.count;i++){
            current=current.next;
            if(i===index){
                return current;
            }
        }
    }
    this.removeAt=(index)=>{
        if(index<0||index>this.count){return 0};
        let current=this.head;
        if(index==0){//第一个
            this.head=this.head.next;
            this.head.next.prev=undefined;
        }else if(index===this.count){//最后一个
            let node=this.getElementAt(index-2);
            node.next=undefined;
        }else{
            let prevNode =this.getElementAt(index-1);
            let currentNode=this.getElementAt(index);
            let nextNode=this.getElementAt(index+1);
            prevNode.next=nextNode;
            nextNode.prev=prevNode;
        }
        this.count--;
//         let current=this.head,prevNode;
      
    }
    this.push=(node)=>{
        if(!node){return};
        this.count++;
        if(!this.head){
            this.head=node;
        }else{
            let current=this.head;
            while (current.next){
                current=current.next;
            };
            current.next=node;
            node.prev=current;
        }
    };
    this.insert=(node,index)=>{
        if(index<0||index>this.count){return};
        let current=this.head;
        this.count++;
        if(index==0){//第一个
            node.next=this.head;
            this.head=node;
        }else if(index===this.count-1){//最后一个
            while(current.next){
                current=current.next;
            }
            current.next=node;
            node.prev=current;
        }else{
            let nextNode,count=0;
            while(current.next){
                current=current.next;
                if(count===index){
                   node.prev=current;
                   node.next=current.next;
                   current.next=node;
                   return;
                }
                count++;
            }
        }
    }
}

function Node(element) {
    this.element = element;
    this.next = undefined;
    this.prev=undefined;
}
var doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.push(new Node("Node0"))
doubleLinkedList.push(new Node("Node1"))
doubleLinkedList.push(new Node("Node2"))
doubleLinkedList.push(new Node("Node3"))
doubleLinkedList.push(new Node("Node4"))
// doubleLinkedList.insert(new Node('headNode'),0);
// doubleLinkedList.insert(new Node("LastNode"),6);
// doubleLinkedList.insert(new Node("node2=>"),2);
// doubleLinkedList.removeAt(2);
// doubleLinkedList.getElementAt(2);

#

树是一种分层数据的抽象模型,从树的根节点出发,他有左子节点以及右子节点组成,其左子节点都会比自己的父节点来得小,右子节点相比父节点会来得大,相比我们常见的数组类似,树的结构更有利与查找树中的值以及删除和移动,而数组更方便的访问具体到某个下标元素,删除移动的性能消耗会相比树的代价更大

function Tree(compareFn){
    this.root=null;
    this.compareFn=compareFn;
    this.search=(key)=>{
        return this.searchNode(this.root,key);
    }
    this.searchNode=(node,key)=>{
        if(node){
            if(node.key===key){
                return true;
            }
            if(compareFn(node,key)){
               node.right&&this.searchNode(node.right,key);
            }else{
               node.left&&this.searchNode(node.left,key);
            }
        }
    }
    this.max=()=>{
        return this.maxNode(this.root);
    }
    this.maxNode=(node)=>{
        let current=node.right;
        while(current.right){
            current=current.right;
        }
        return current;
    }
    this.min=()=>{
        return this.minNode(this.root);
    }
    this.minNode=(node)=>{
        let current=node;
        while(current.left){
            current=current.left;
        }
        return current;
    }
    this.inOrderTraverse=(callback)=>{
        this.inOrderTranverseNode(this.root,callback);
    }
    this.preOrderTraverse=(callback)=>{
        this.preOrderTraverseNode(this.root,callback);
    }
    this.preOrderTraverseNode=(node,callback)=>{
        if(node){
            callback(node);
            this.preOrderTraverseNode(node.left,callback);
            this.preOrderTraverseNode(node.right,callback);
        }
    }
    this.inOrderTranverseNode=(node,callback)=>{
        if(node){
            this.inOrderTranverseNode(node.left,callback);
            callback(node);
            this.inOrderTranverseNode(node.right,callback);
        }
    }
    this.insert=(key)=>{
        if(!this.root){
            let node =new Node(key);
            this.root=node;
        }else{
            this.insertNode(this.root,key);
        }
    }
    this.insertNode=(node,key)=>{
        if(this.compareFn(node,key)){
            if(!node.right){
                node.right=new Node(key);
            }else{
                this.insertNode(node.right,key)
            }
        }else{
            if(!node.left){
                node.left=new Node(key);
            }else{
                this.insertNode(node.left,key)
            }
        }
    }
}
function compareFn(node,key){
    if(node.key>key){
        return false;
    }
    return true;
}
function Node(key){
    this.key=key;
    this.left=null;
    this.right=null;
}
var tree=new Tree(compareFn);
tree.insert(11);
tree.insert(7);
tree.insert(15);
tree.insert(5);
tree.insert(3);
tree.insert(9);
tree.insert(8);
tree.insert(10);
tree.insert(13);
tree.insert(12);
tree.insert(14);
tree.insert(20);
tree.insert(18);
tree.insert(25);
tree.insert(6);
// tree.inOrderTraverse((node)=>{
//     console.log(node)
// })
// tree.preOrderTraverse((node)=>{
//     console.log(node)
// })
tree.min();
tree.max();
var node=tree.search(25)
console.log(123,node)

# 节点

每个节点都有 left 和 right 属性,表明该节点的左子节点和右子节点的指针。

然后我们要实现一些基本的增删改查的方法。

  • insert(key) 向树中插入新的键
  • search(key) 查找到某个节点并返回
  • inOrderTraverse(callback) 中序遍历
  • prevOrderTraverse(callback) 先序遍历
  • postOrderTraverse(callback) 后序遍历
  • remover(key) 删除节点
  • min() 查找最小值
  • max() 查找最大值
// 浏览器脚本开发,使用class对象时无法动态刷新并提示对象已申明,故使用函数来实现
//节点对象
function Node(key) {
  this.key = key
  this.left = null
  this.right = null
}
//树
function Tree(compFn) {
  this.root = null //根结点
  this.count = 0 //节点数量
  this.compFn = compFn //比较函数,可传入自定义比较函数

  this.remove = key => {
    return this.removeNode(this.root, key) //传入根结点进行递归
  }
  this.removeNode = (node, key) => {
    //递归函数查找到要删除的节点
    const result = this.compFn(node.key, key) //目标key与当前node的key进行比较,进行折半查找(二分查找)
    if (result === true) {
      node.right = this.removeNode(node.right, key) //大于当前节点时往右查找并递归
      return node
    }
    if (result === false) {
      node.left = this.removeNode(node.left, key) //同理,小于则向左查找
      return node
    }
    if (result === 1) {
      //执行到此处时已经相等,找到了当前的值的节点
      if (!node.left && !node.right) {
        //如果左子节点和右子节点都不存在则直接删除
        node = null
        return node
      }
      if (node.left && !node.right) {
        //仅有左子节点存在时直接把左子节点网上上移即可
        node = node.left
        return node
      }
      if (!node.left && node.right) {
        // 仅有右子节点时同理
        node = node.right
        return node
      }
      if (node.left && node.right) {
        //左右子节点同时存在时我们只要右子节点下最小的节点的key替换掉就好
        const rightMinNode = this.getMinNode(node.right) //获取到右子节点下最小的节点
        node.key = rightMinNode.key //替换为右子树最小节点的key
        this.removeNode(node, rightMinNode.key) //再删除原有右子树最小节点
        return node
      }
    }
  }
  this.search = key => {
    return this.searchNode(this.root, key)
  }
  this.searchNode = (node, key) => {
    //查询节点
    const result = this.compFn(node.key, key) //目标key与当前node的key进行比较,进行折半查找(二分查找)
    if (result === true) {
      return this.searchNode(node.right, key) //大于当前节点时往右查找并递归
    }
    if (result === false) {
      return this.searchNode(node.left, key) //同理,小于则向左查找
    }
    if (result === 1) {
      //已经找到
      return node
    }
  }
  this.max = () => {
    return this.getMaxNode(this.root)
  }
  this.getMaxNode = node => {
    //最大值,最右侧就是最大值,递归node.right即可
    if (!node.right) {
      return node
    } else {
      return this.getMaxNode(node.right)
    }
  }
  this.min = () => {
    return this.getMinNode(this.root)
  }
  this.getMinNode = node => {
    //最小值同理,最右侧的节点,递归node.left即可
    if (!node.left) {
      return node
    } else {
      return this.getMinNode(node.left)
    }
  }
  this.insert = function(key) {
    //插入节点
    if (this.root) {
      //更节点存在时执行插入
      this.insertNode(this.root, key)
    } else {
      //没有根结点时直接设为根结点
      this.count++
      this.root = new Node(key)
    }
  }
  this.insertNode = function(node, key) {
    //插入节点迭代函数
    if (this.compFn(node.key, key)) {
      //如果插入的节点大于当前node的key
      if (!node.right) {
        //如果node的右子节点没有节点指向时
        node.right = new Node(key) //直接设置为该节点right为插入的节点
        this.count++ //树量+1
      } else {
        this.insertNode(node.right, key) //否则再次递归
      }
    } else {
      if (!node.left) {
        //同理,如果左侧子节点没有指向时插入该节点
        this.count++
        node.left = new Node(key)
      } else {
        this.insertNode(node.left, key) //递归
      }
    }
  }
  this.prevOrderTraverse = function(callback) {
    //先序遍历
    this.root && this.prevOrderTraverseNode(this.root, callback)
  }
  this.prevOrderTraverseNode = function(node, callback) {
    //迭代遍历所有的节点,具体的遍历顺序可百度对应的图片,比较好理解
    callback(node)
    node.left && this.prevOrderTraverseNode(node.left, callback)
    node.right && this.prevOrderTraverseNode(node.right, callback)
  }
  this.inOrderTraverse = function(callback) {
    //中序
    if (this.root) {
      this.inOrderTraverseNode(this.root, callback)
    }
  }
  this.inOrderTraverseNode = function(node, callback) {
    //先序😀迭代遍历所有的节点,具体的遍历顺序可百度对应的图片,比较好理解
    node.left && this.inOrderTraverseNode(node.left, callback)
    callback(node)
    node.right && this.inOrderTraverseNode(node.right, callback)
  }
}

var tree = new Tree((left, rg) => {
  if (left > rg) {
    return false
  } else if (left < rg) {
    return true
  } else {
    return 1
  }
})
tree.insert(1)
tree.insert(2)
tree.insert(3)
tree.insert(4)
tree.insert(5)
tree.insert(-1)
tree.prevOrderTraverse(node => {
  console.log(node)
})
console.log("min", tree.min())
console.log("max", tree.max())
console.log("search", tree.search(4))
console.log("remove", tree.remove(2))

# 自平衡(AVL)

普通的二叉搜索树(BST)存在很多问题,想上面的样子,我们就很容易发现,每次按顺序插入比他大一的 key,每次都会插入到节点的右边,而造成左边的深度远远大于右边,这样在执行插入某些特定的值时,就会引发一些性能上多余的消耗,为了解决这个问题,我们规定了 AVL-自平衡二叉搜索树,每个节点的左右两侧的紫薯的深度的差别最多为一,很好的保持的树的平衡性。

AVL 树和普通树插入搜索完全相同,然而不同之处是我们需要检查他的平衡因子,使其在每次操作时自动保持平衡,又引出了几个新的概念

# 1.节点的高度和平衡因子

节点高度是从任意节点到其最后子节点的最高高度,在 AVL 中我们通过计算其差值来进行对应的树旋转操作,只要是树的高度之间差值为 -2,2 都算是不平衡状态,此时我们需要手动旋转树,将它“平衡”起来,即高度差值为 0。这就是平衡因子的概念了,

计算树节点的高度迭代函数:

this.getNodeHegiht = node => {
  if (!node) {
    return -1
  }
  //使用迭代求出左子节点和右子节点中大的那一个数,即该节点的高度
  return (
    Math.max(this.getNodeHegiht(node.left), this.getNodeHegiht(node.right)) + 1
  )
}

# 2.平衡操作(AVL 旋转)

  • LL 左左 -向左单旋转
this.rotationLL = node => {
  const temp = node.left
  node.left = temp.right
  temp.right = node
  node = temp
  return node
}
  • RR -向右的单旋转
this.rotationRR = node => {
  const temp = node.right
  node.right = temp.left
  temp.left = node
  node = temp
  return node
}
  • LR 向右的双旋转(先 LL 旋转,再 RR 旋转)
this.rotationLR = node => {
  node.left = this.rotationRR(node.left)
  return this.rotationLL(node)
}
  • RL 向左的双旋转 (先 RR 旋转,再 LL 选装)
this.rotationRL = node => {
  node.left = this.rotationLL(node.left)
  return this.rotationRR(node)
}

# 3.AVL 修改节点插入函数

AVL 与普通搜索树很多特性是一样的,我们可以先继承搜索树,只要继承二叉搜索树然后修改插入方法即可,主要是在我们插入时检查节点的深度是否满足 AVL 要求,没有满足我们对其做对应的旋转操作。

var BlanceFactor = {
  //判断旋转类型,使用symbol可不用赋值,避免赋值重复造成不必要的错误
  UNBLANCED_RIGHT: Symbol(),
  UNBLANCED_LEFT: Symbol(),
  SINGLE_UNBLANCED_RIGHT: Symbol(),
  SINGLE_UNBLANCED_LEFT: Symbol(),
  BLANCED: Symbol()
}
function AVLTree() {
  Tree.call(this)
  //继承的n种方式
  this.insert = key => {
    //修改插入方法
    if (!this.root) {
      this.root = new Node(key)
      this.count++
    } else {
      this.insertNode(this.root, key)
    }
  }
  this.insertNode = (node, key) => {
    //与二叉搜索树一致
    if (this.compFn(node.key, key) === true) {
      if (!node.right) {
        node.right = new Node(key)
        this.count++
      } else {
        this.insertNode(node.right, key)
      }
    } else if (this.compFn(node.key, key) === false) {
      if (!node.left) {
        this.count++
        node.left = new Node(key)
      } else {
        this.insertNode(node.left, key)
      }
    } else {
      //否则节点key相等则直接返回,不插入
      return node
    }
    //此处我们要获取节点深度差别来进行AVL旋转
    const nodeStatus = this.getBlanceFactor(node)
    if (nodeStatus == BlanceFactor.UNBLANCED_LEFT) {
      //LL 即差值等于2,左边比右边多两个
      console.log(node, "LL")
      if (this.compFn(node.key, key) === false) {
        //节点的key小于要插入的key
        node = this.rotationLL(node) //执行LL旋转
      } else {
        return this.rotationLR(node) //否则执行LR旋转
      }
    } else if (nodeStatus == BlanceFactor.UNBLANCED_RIGHT) {
      //同理
      console.log(node, "RR")
      if (this.compFn(node.key, key) === true) {
        node = this.rotationRR(node)
      } else {
        return this.rotationRL(node)
      }
    }
    return node
  }
  //树旋转,具体操作可以百度下AVL旋转图解更形象

  this.rotationLR = node => {
    node.left = this.rotationRR(node.left)
    return this.rotationLL(node)
  }
  this.rotationRL = node => {
    node.left = this.rotationLL(node.left)
    return this.rotationRR(node)
  }
  this.rotationRR = node => {
    const temp = node.right
    node.right = temp.left
    temp.left = node
    node = temp
    return node
  }
  this.rotationLL = node => {
    const temp = node.left
    node.left = temp.right
    temp.right = node
    node = temp
    return node
  }

  this.getBlanceFactor = node => {
    var heightDifferent =
      this.getNodeHegiht(node.left) - this.getNodeHegiht(node.right)
    switch (
      heightDifferent //返回差值对应的状态
    ) {
      case 0:
        return BlanceFactor.BLANCED
      case 1:
        return BlanceFactor.SINGLE_UNBLANCED_LEFT
      case 2:
        return BlanceFactor.UNBLANCED_LEFT
      case -1:
        return BlanceFactor.SINGLE_UNBLANCED_RIGHT
      case -2:
        return BlanceFactor.UNBLANCED_RIGHT
    }
  }
  this.getNodeHegiht = node => {
    //获取节点深度
    if (!node) {
      return -1
    }
    return (
      Math.max(this.getNodeHegiht(node.left), this.getNodeHegiht(node.right)) +
      1
    )
  }
}

var tree = new AVLTree()
tree.insert(1)

tree.insert(4)
tree.insert(5)
tree.insert(6)
tree.insert(7)
tree.insert(8)
tree.insert(9)
tree.insert(10)

// tree.insert(5);
// tree.insert(-1)

# 红黑树(RBTree)

自平衡树也是红黑树的一种,AVL 中插入可能会对树进行旋转,如果插入频率比较低,那么 AVL 树会比红黑树更适合。

# 红黑树特性

  • 每个节点不是红的就是黑的
  • 根结点都是黑的
  • 所有叶节点都是黑的
  • 如果一个节点是红的,那么他两个子节点是黑的
  • 相同节点的父节点或者子节点都是不同的
  • 相同层次的节点的红黑属性也应该是相同的

# 红黑树节点

var COLOR = {
  RED: Symbol(),
  BLACK: Symbol()
}
function RBNode(key) {
  Node.call(this, key) //继承普通节点属性
  this.color = COLOR.RED //给个颜色
  this.parent = null //父节点
  this.isRed = () => this.color === COLOR.RED //是否为红
}

# 哈夫曼编码压缩原理