数据结构与算法

1 栈

先进后出

1.1 栈的操作

push:添加一个元素到栈顶
pop:移除栈顶元素,同时返回被移除的元素
peek:返回栈顶元素
isEmpty:如果栈没有任何元素就返回true
size:栈元素的个数
toString:将栈结构内容以字符串形式返回

1.2 栈结构的实现

function Stack(){
	this.items=[]
	Stack.prototype.push=function(element){
		this,items.push(element)
	}
	Stack.prototype.pop=function(){
		return this.items.pop()
	}
	Stack.prototype.peek=function(){
		return this.items[this.items.length-1]
	}
	Stack.prototype.isEmpty=fucntion(){
		return this.items.length===0
	}
	Stack.prototype.size=function(){
		return this.items.length	
	}
	Stack.prototype.toString=function(){
		return this.items.join('')	
	}

}

2 队列

先进先出,只允许在表前端进行删除,在表后端进行插入

2.1 队列的操作

enqueue:向队列尾部添加一个元素
dequeue:移除队列的第一项,并返回被移除的元素
front:返回队列的第一个元素

2.2 队列的实现

function queue(){
  this.items=[]
  queue.prototype.enqueue=function(element){
    this.items.push(element)
  }
  queue.prototype.dequeue=function(){
    return this.items.splice(0,1)
  }
  queue.prototype.front=function(){
    return this.items[0]
  }
}

2.3 实现击鼓传花

function passGame(group,num){
	var queue=new Queue()
	group.forEach(p=>queue.enqueue(p))
	var queue=new Queue()
	group.forEach(p=>{
    queue.enqueue(p)
  })
  let count=0
  while(queue.size()>1){
    if(count===num-1){
      queue.dequeue()
      count=0
    }
    queue.enqueue(queue.dequeue())
    count++
  }
}

2.4 优先级队列

function PriorityQueue(){
  function QueueElement(element,priority){
    this.element=element
    this.priority=priority
  }
  this.items=[]
  PriorityQueue.prototype.enqueue=function(element,priority){
    var queueElement=new QueueElement(element,priority)
    if (this.items.length===0){
      this.items.push(queueElement)
    } else{
      var add=false
      for(let i=0;i<this.items.length;i++){
        if(queueElement.priority<this.items[i].priority){
            this.items.splice(i,0,queueElement)
            add=true
            break
        }
      }
      if(!add){
        this.items.push(queueElement)
      }

    }  
  }
  PriorityQueue.prototype.dequeue=function(){
    return this.items.shift()
  }
  PriorityQueue.prototype.front=function(){
    return this.items[0]
  }
  PriorityQueue.prototype.isEmpty=function(){
    return this.items.length===0
  }
  PriorityQueue.prototype.size=function(){
    return this.items.length
  }
  PriorityQueue.prototype.toString=function(){
    return this.items.join('')
  }
}

3 链表

链表的每一个元素由一个存储元素本身的节点和一个指向下一个元素的引用组成

缺点:
1、链表访问任何位置的元素时,都需要从头开始访问
2、无法通过下标访问元素

3.1 链表常见操作

append:向链表尾部添加一个元素
insert:向链表的特定位置插入一个新的项
get:获取对应位置的数据
indexOf:返回元素在列表中的索引
update:修改某个位置的元素
removeAt:从链表特定位置移除一项
remove:移除一项

3.2 链表的实现

function Linklist(){

  function Node(data){
    this.data=data
    this.next=null
  }
  this.head=null
  this.length=0

  Linklist.prototype.append=function(data){
    var newNode=new Node(data)
    if(this.length===0){
      this.head=newNode
    }else{
      var current=this.head
      while(current.next){
        current=current.next
      }
      current.next=newNode
    }
    this.length++
  }
  Linklist.prototype.toString=function(){
    var current =this.head
    var res=""
    while(current){
      res+=current.data
      current=current.next
    }
    return res
  }
  Linklist.prototype.insert=function(index,data){
    if(index<0||index>this.length)return false
    var current=this.head
    var prev=null
    var newNode=new Node(data)
    if(index===0){
      this.head=newNode
      newNode.next=current
      this.length++
    }else{
      let i=0
      while(i++<index){
        prev=current
        current=current.next
      }
      newNode.next=current
      prev.next=newNode
      this.length++
    }


  }
  Linklist.prototype.get=function(index){
    if(index<0||index>this.length-1)return false
    var current=this.head
    var i=0
    while(i++<index){
      current=current.next
    }
    return current
  }
  Linklist.prototype.indexOf=function(data){
    var current=this.head
    let i=0
    while(i<this.length){
      if(current.data===data){
        return i
      }
      current=current.next
      i++
    }
    return false
  }
  Linklist.prototype.update=function(index,data){
    if(index<0||index>this.length-1)return 0
    var current=this.head
    let i=0
    while(i++<index){
      current=current.next
    }
    current.data=data
  }
  Linklist.prototype.removeAt=function(index){
    if(index<0||index>this.length-1)return false
    if(index===0){
      this.head=this.head.next
      this.length--
    }
    var current=this.head
    var prev=null
    let i=0
    while(i++<index){
      prev=current
      current=current.next
    }
    prev.next=current.next
    this.length--
  }
  Linklist.prototype.remove=function(data){
    var current=this.head
    var prev=null
    let i=0
    while(i<this.length){
      if(current.data===data){
        if(i===0){
          this.head=current.next
          this.length--
          break
        }else{
          prev.next=current.next
          this.length--
        }
      }
      prev=current
      current=current.next
      i++
    }
  }
  Linklist.prototype.size=function(){
    return this.length
  }
  Linklist.prototype.isEmpty=function(){
    return this.length===0
  }
}

4 集合

add:向集合添加一个新元素
remove:向集合移除一个值
has:如果值在集合中,返回true
clear:清除集合中所有项
size:返回集合包含的所有元素
values:返回一个包含集合中所有值的数组

4.1 集合的实现

function Set(){
  this.items={}

  Set.prototype.add=function(value){
    if(this.has(value)){
      return false
    }
    this.items[value]=value
  }
  Set.prototype.has=function(value){
    return this.items.hasOwnProperty(value)
  }
  Set.prototype.remove=function(value){
    if(this.has(value)){
      delete this.items[value]
      return true
    }
    return false
  }
  Set.prototype.clear=function(){
    this.items={}
  }
  Set.prototype.size=function(){
    return Object.keys(this.items).length
  }
  Set.prototype.values=function(){
    let arr=[]
    Object.keys(this.items).forEach(key=>arr.push(this.items[key]))
    return arr
  }
  //求并集
  Set.prototype.union=function(otherSet){
    var union=new Set()
    var values=this.values()
    values.forEach(val=>union.add(val))
    otherSet.values().forEach(val=>{
      if(!union.has(val)){
        union.add(val)
      }
    })
    return union.values()
  }
  //求交集
  Set.prototype.inter=function(otherSet){
    var union=new Set()
    var values=this.values()
    values.forEach(val=>{
      if(otherSet.has(val)){
        union.add(val)
      }
    })
    return union.values()
  }
  //求差集
  Set.prototype.diff=function(otherSet){
    otherSet.values().forEach(val=>{
      if(this.has(val)){
        this.remove(val)
      }
    })
    return this.items
  }
  //求子集
  Set.prototype.subset=function(otherSet){
    let flag=true
    otherSet.values().forEach(val=>{
      if(!this.has(val)){
        flag=false
      }
    })
    return flag
  }
}

5 哈希表

哈希化:将大数字转化成数组范围内下标的过程
哈希冲突:将字符串转化成下标的过程出现重复,导致有两个字符串对应于同一个位置
解决哈希冲突的方法:链地址法、开放地址法

哈希表的长度最好使用质数,质数使分布更加均匀

5.1 哈希表的实现

function HashTable(){
  this.storage=[]
  this.count=0
  this.limit=7
  HashTable.prototype.hashFunc=function(str,size){
    var hashcode=0
    for(let i=0;i<str.length;i++){
      hashcode=37*hashcode+str.charCodeAt(i)
    }
    index=hashcode%size
    return index
  }
  HashTable.prototype.insert=function(key,value){
    var index=this.hashFunc(key,this.limit)
    var bucket=this.storage[index]
    if(bucket==null){
      bucket=[]
      this.storage[index]=bucket
    }

    for(let i=0;i<bucket.length;i++){
      var tuple=bucket[i]
      if(tuple[0]===key){
        tuple[1]=value
        return 
      }
    }
    bucket.push([key,value])
    this.count++
    if(this.count>this.limit*0.75){
      var newSize=this.limit*2
      var newPrime=this.getPrime(newSize)
      this.resize(newPrime)
    }

  }
  HashTable.prototype.get=function(key){
    var index=this.hashFunc(key,this.limit)
    var bucket=this.storage[index]
    if(bucket==null)return null
    for(let i=0;i<bucket.length;i++){
      var tuple=bucket[i]
      if(tuple[0]===key)return tuple[1]
    }
    return null
  }
  HashTable.prototype.remove=function(key){
    var index=this.hashFunc(key,this.limit)
    var bucket=this.storage[index]
    if(bucket==null)return false
    for(let i=0;i<bucket.length;i++){
      var tuple=bucket[i]
      if(tuple[0]===key){
        bucket.splice(i,1)
        this.count--
        if(this.limit<7  &&this.count<this.limit*0.25){
          var newSize=Math.floor(this.limit/2)
          var newPrime=this.getPrime(newSize)
          this.resize(newPrime)
        }
        return tuple[1]  
      }
    }
  }
  HashTable.prototype.isEmpty=function(){
    return this.count==0
  }
  HashTable.prototype.size=function(){
    return this.count
  }
  HashTable.prototype.resize=function(newLimit){
    var oldStorage=this.storage
    this.storage=[]
    this.count=0
    this.limit=newLimit

    for(let i=0;i<oldStorage.length;i++){
      var bucket=oldStorage[i]
      if(bucket===null){
        continue
      }
      for(let j=0;j<bucket.length;j++){
        var tuple=bucket[j]
        this.insert(tuple[0],tuple[1])
        this.count++
      }

    }
  }
  HashTable.prototype.isPrime=function(num){
    for(let i=2;i<=parseInt(Math.sqrt(num));i++){
      if(num%i===0){
        return false
      }
    }
    return true
  }
  HashTable.prototype.getPrime=function(num){
    while(!this.isPrime(num)){
      num++
    }
    return num
  }
}

5.2 判断一个数是质数

只能被1和自己整除

function isPrime(num){
	for(let i=2;i<=parseInt(Math.sqrt(num));i++){
		if(num%i===0){
			return false
		}
	}
	return true
}

6 树

二叉搜索树:非空左子树的键值小于根节点的键值,非空右子树的所有键值大于根节点的键值

二叉搜索树的常见操作:
insert:向书中插入一个新的键
search:查找一个键
inOrderTraverse:通过中序遍历方式遍历所有节点
preOrderTraverse:通过先序遍历方式遍历所有节点
postOrderTraverse:通过后序遍历方式遍历所有节点
remove:从树中移除某个键

(1)先序遍历
先访问根节点,在先序遍历左子树,再先序遍历右子树

(2)中序遍历
先中序遍历左子树,访问根节点,再中序遍历右子树

(3)后序遍历
先后序遍历左子树,再后序遍历右子树,最后访问根节点

6.1 二叉搜索树的实现

function BinarySearchTree(){
  function Node(key){
    this.key=key
    this.left=null
    this.right=null
  }
  this.root=null

  BinarySearchTree.prototype.insert=function(key){
    var node=new Node(key)
    if(!this.root){
      this.root=node
    }else{
      this.insertNode(this.root,node)
    }
  }
  BinarySearchTree.prototype.insertNode=function(node,newNode){
    if(newNode.key<node.key){
      if(!node.left){
        node.left=newNode
      }else{
        this.insertNode(node.left,newNode)
      }
    }else{
      if(!node.right){
        node.right=newNode
      }else{
        this.insertNode(node.right,newNode)
      }
    }
  }
  BinarySearchTree.prototype.preorderTraverse=function(handler){
    this.preorderTraverseNode(this.root,handler)
  }
  BinarySearchTree.prototype.preorderTraverseNode=function(node,handler){
    if(!node)return null
    handler(node.key)
    node.left&&this.preorderTraverseNode(node.left,handler)
    node.right&&this.preorderTraverseNode(node.right,handler)
  }
  BinarySearchTree.prototype.inorderTraverse=function(handler){
    this.inorderTraverseNode(this.root,handler)
  }
  BinarySearchTree.prototype.inorderTraverseNode=function(node,handler){
    if(!node)return null
    node.left&&this.inorderTraverseNode(node.left,handler)
    handler(node.key)
    node.right&&this.inorderTraverseNode(node.right,handler)
  }
  BinarySearchTree.prototype.postorderTraverse=function(handler){
    this.postorderTraverseNode(this.root,handler)
  }
  BinarySearchTree.prototype.postorderTraverseNode=function(node,handler){
    if(!node)return null
    node.left&&this.inorderTraverseNode(node.left,handler)
    node.right&&this.inorderTraverseNode(node.right,handler)
    handler(node.key)
  }
  BinarySearchTree.prototype.max=function(){
    var node=this.root
    while(node.right){
      node=node.right
    }
    return node.key?node.key:null
  }
  BinarySearchTree.prototype.min=function(){
    var node=this.root
    while(node.left){
      node=node.left
    }
    return node.key?node.key:null
  }
  BinarySearchTree.prototype.search=function(key){
    var node=this.root
    while(node){
      if(node.key>key){
        node=node.left
      }else if(node.key<key){
        node=node.right
      }else{
        return true
      }
    }
    return false
  }
  BinarySearchTree.prototype.remove=function(key){
    //先查找节点
    var node=this.root
    var isLeftChild=true
    var parent=null
    while(node.key!==key){
      parent=node
      if(key<node.key){
        node=node.left
        isLeftChild=true
      }else if(key>node.key){
        node=node.right
        isLeftChild=false
      }
      if(node===null)return false
    }

    // 找到节点后判断子节点
    if(!node.left&&!node.right){
      
      if(node==this.root){
        this.root=null
      }else{
        // 子节点不存在,直接删除,并让父节点指向为空
        if(isLeftChild){
          parent.left=null
        }else{
          parent.right=null
        }
      }
    }else if(!node.left||!node.right){
      if(node==this.root){
        this.root=node.left||node.right
      }else{
        // 只存在一个子节点
        if(isLeftChild){
          parent.left=node.left||node.right
        }else{
          parent.right=node.left||node.right
        }
      }
    }else{
      // 存在两个子节点
      // 从左子树中找最大的,右子树中找最小的
      var delNode=this.getSuccess(node)
      if(node==this.root){
        this.root=delNode
      }else{
        if(isLeftChild){
          parent.left=delNode
        }else{
          parent.right=delNode
        }
      }
      delNode.left=node.left

      
    }
  }
  BinarySearchTree.prototype.getSuccess=function(delNode){
    var replaceNode=delNode
    var current=delNode.right
    var replaceNodeParent=delNode
    while(!current){
      replaceNodeParent=replaceNode
      replaceNode=current
      current=current.left
    }
    if(replaceNode!==delNode.right){
      replaceNodeParent.left=delNode.right
      replaceNode.right=delNode.right
      
    }
    return replaceNode
  }

}

7 图论

function Graph(){
  this.vertexes=[]
  this.edges=new Dictionary()

  Graph.prototype.addVertex=function(v){
    this.vertexes.push(v)
    this.edges.set(v,[])
  }
  Graph.prototype.addEdge=function(v1,v2){
    this.edges.get(v1).push(v2)
    this.edges.get(v2).push(v1)
  }
  Graph.prototype.initializeColor=function(){
    var color=[]
    for(let i=0;i<this.vertexes.length;i++){
      color[this.vertexes[i]]='white'
    }
    return color
  }
  Graph.prototype.bfs=function(initV){
    var queue=new Queue()
    var color=this.initializeColor()
    let res=''
    queue.enqueue(initV)
    while(!queue.isEmpty()){
      let v=queue.dequeue()
      let vList=this.edges.get(v)
      color[v]='grey'
      for(let i=0;i<vList.length;i++){
        let e=vList[i]
        if(color[e]=='white'){
          queue.enqueue(e)
          color[e]='grey'
        }
      }
      res+=v
     
      color[v]='black'
    }
    return res
  }
  Graph.prototype.dfs=function(initV){
    let color=this.initializeColor()
    let res=[]

    const dfsVisit=function(v,color){
      color[v]='grey'
      let vList=this.edges[v]
      for(let i=0;i<vList.length;i++)
      {
        let e=vList[i]
        if(color[e]=='white'){
          dfsVisit(e,color)
        }
      }
      color[v]='black'
    }
    dfsVisit(initV,color)
  }
}

大O表示法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值