数据结构与算法

1.栈的概念

自己的理解是:栈的结构是一种后进先出的结构(遵循 LIFO 原则),栈的操作有入栈出栈,栈顶,栈底,检查栈顶,清空检查个数这种操作。栈实现了一个进制装换算法:余数法。

栈的作用:在编程语言的编译器和内存中保存变量,方法和调用。栈和函数(函数调用时入栈跟出栈)。栈是一个基本的计算机数据结构是高级编程语言的实现基础。

递归:如果是不停的递归而不出栈,会导致栈溢出,后面死机了。递归的意思就是函数调用自己本身。

问题:1.栈和队列的区别:

2.tcp/ip协议和http协议是啥

3冒泡排序和归并排序的区别

 

var stack = function(){
    var items = []

    this.push = function(element){
        items.push(element)
    }
}

// pop
this .pop = function(){
    return items.pop()
}


//peek 检查栈顶
this.peek = function(){
    return items[item.length-1]
}

//检查栈 是否为空
this.isEmpty = function(){
    return items.length == 0
}

//清除线
this.clear = function(){
    items = []
}

//获取栈的大小
this.size = function(){
    return items.length
}


//检查items 
this.getItems = function(){
    return items
}


//10转2
var divBy2 = function(number){
    var stack = new Stack()
    var yushu

    var string2=""

    while(number > 0){
        yushu = number % 2
        stack.push(yushu)
        number = Math.floor(number / 2)
    }
    while(!stack.isEmpty()){
        string2 += stack.pop()
    }

    return string2

}

2.队列的概念

队列是使用类来封装队列 操作

添加在最后一项push,删除下标索引号第0个用shift(头部),删除下标索引号最后一个用pop(尾巴)

先进先出

优先级 priorityQueue

splice 切割

队列 =》 优先队列
var PriorityQueue = function(){
    var items = []
}

//辅助类
var QueueItem = function(element,priority ){
    this.element = element
    this.priority = priority
}
this.enqueue = function (element,priority) {
    var QueueItem = new QueueItem(element,priority)
    
    var added = false
    
    for(var i = 0; i < items.length ; i++){
        if(QueueItem.priority > items[i].priority){
            items.splice(i, 0, QueueItem)
            added = true
            break
        }
    }
    if (!added){
        items.push(QueueItem)
    }
    this.getItems = function () {
        return items
    }
}

var pq = new PriorityQueue()
pq.enqueue("小黑",10)
pq.enqueue("小明",12)
var Queue = function(){
    var item =[]

    //入队
    this.enqueue = function(element){
        item.push(element)
    }

    //出队
    this.dequeue = function(){
        return item.shift(element)
    }

    //查看队列头
    this.front = function(){
        return item(0)
    }

    //检查队列是否为空
    this.isEmpty = function(){
        return items.length === 0
    }

    //检查队列的大小
    this.size = function(){
        return items.length()
    }
}

3.链表

什么是链表:可以想成火车,火车头连接到连接到火车尾巴。一环扣一环。链表是没有下标的。

链表头插入元素:insert(position,element)

链表尾获取元素索引:indexsof(element)

尾部添加元素:append(element)

复用代码:remove()链表中移除一项;indexof()获取元素索引;removeAt()链表中特定位置移除

 

 

 

var LikedList = function(){

    //链表头

    var head = null //object nulll

    //链表长度

    var length = 0

   

    //辅助类节点

    var Node = function(element){

        this.element = element

        this.next = null


 

    }

   

    //链表尾部添加元素

    this.apped = function(element){

        var node = new Node(element)

    //nade ={element:element   next :null}

    }

   

    if (head == null){

        head = node

   

    } else {

        var current = head

        while(current.next){

            current = current.next

        }

        //while 循环执行之后,current已经是链表最后一项

        current.next = node

    }

    length++

}

this.getHead = function(){

    return head

}

current=head 意思是当前

 

  

//链表的某个位置添加元素
this.insert = function(position,element){
    //越界问题
    if(position > -1 && position < length){
        var node = new Node(element)
        if(position == 0){
            var current = head;
            head = node 
            head.next = current
        } else {
            var index = 0
            var current = head
            var previous = null
            while(index < position){
                previos = current
                current = current.next
                index++

            }
            previous.next = node
            node.nexs = current
        }
        length++
    }

}


this.getHead = function(){
    return head
}

var l = new LikedList
l.apped(1)
l.apped(2)
l.apped(3)

l.insert (1,10)

//1  10  2  3

作业练习代码:

function Node(name, next) {
    this.name = name;
    this.next = next;
}

// 制造数据
var C = new Node("C",null);
var B = new Node("B",C);
var A = new Node("A",B);

// 创建链表
A

// 在A后插入D
var D = new Node("D",null);
console.log(A.next.name);//B
var tmp = A.next;
A.next = D; 
D.next = tmp;

// 作业:改为只有A(表头)
A.next.name=A.next.next.name 
A.name = A.next.name





// 删除B
D.next = C;
// 作业:改为只有A(表头)


// 输出所有的结点的name
console.log(A.name);
console.log(A.next.name);
console.log(A.next.next.name);

var tmp = A;
while(tmp!=null) {
    console.log(tmp.name);
    tmp = tmp.next;
}

常见的报错。另外学习DMA中断   操作系统,资源竞争,科学家就餐,生产者消费者,银行排队,分时时间片等的算法。

 

4,集合

  1. 集合概念:集合是一种数学中的概念。特性:(1)无重复性。(2)空集。(3)子集。
  2. 我们用来构建集合框架的东西就是对象:var set = function(){var item = {};}

var Set2 = function(){
    var item ={}
    
    //has 检查元素是否存在 return boolean
    this.has = function(){
        return items.hasOwnProperty(value)
    }

    //add添加元素,集合不重复
    this.add = function(value){  //value = 3
       // if (!this.has)
       if (!this.has(value)){
            //true 存在
            return false
       } else{
            //false 不存在
            item[value] = value
            //items[3]=3
            //方括号语法,点语法
            return value 
       }
    }

    //移除元素
    this.remove = function(value) {
        if(this.has(value)){
            //拿出来用
            delete items[value]
            return true
        } else{
            //不管用
            return false
        }
    }
    //清空集合
    this.clear = function(){
        items={}
    }
    //size集合长度大小
    this.size = function () {
        //遍历集合
        var count = 0
        for(var i in item){
            count++;
            console.log(i);
        }
        return count
    }




    //检查程序
    this.getItems = function(){
        return items
    }
}

5,字典散列表

  1. 字典的学习是一种类似集合的数据结构
  2. 键值对
  3. 字典的主要操作:添加键值对:set(key,value)通过键值对移除元素 delete(key) 检查健has(key)  由健获取值get(key)  。用 JavaScript 的 in 运算符来验证给定元素是否是 items 对象的属性如“name”in book 或‘price’ in book
  4. 散列表操作方法:添加元素put(key,value),移除值remove(key),检索值get(key)
  5. export default class Dictionary 导出默认类字典
  6. 哈希表也叫散列表,有分离链接法,和线性探性查法
  7. loseloseHashCode是将一个key散列值出一个算法,存在缺陷,重复率太高,所以我们才要用分离链接法和线性探查法来避免这种重复。
  8. 分离链接法是结合了链表
  9. 线性探查
  10. 栈跟队列是通过数组实现的,链表是通过字面量实现的,集合跟字典是通过对象实现的

6,树

  1. 树结构的核心就是一个个节点辅助类
  2. 我,们遍历树的话必须有个递归,所以我们要有个辅助函数,对外部不可暴露复杂的方法,所以只能用简单的方法操作他,内部相对复杂一点。(1)添加节点。(2)查找节点。(3)遍历节点。(4)删除节点
  3. 二叉树定律
  4. 插入数据的时候要判断树是不是空的,树是空就设置为根节点,树不是空的,对比值。Root是null也就说明树是空的。如果不是空就对比值大小在对应的位置
  5. 什么叫递归呢:var fn=function(){fn()}fn()   调用自己本身   1,递归的出口在哪里
  6. 插入节点: 
    var root = null;
        //插入节点
        var insertNode = function (node, newNode) {   //首先要实现个方法,它接受两个参数一个是node一个newNode
            if (newNode.value > node.value) {
                //往右走
                if (node.right == null) {
                    node.right = newNode
                } else {
                    insertNode(node.right,newNode)
                }
            } else if (newNode.value < node.value) {
                //往左走
                if (node.left == null) {
                    node.left = newNode
                } else {
                    insertNode(node.left,newNode)
                }
            }
        }
        this.insert = function (value) {
            var newNode = new Node(value)  //newNode是新的节点
            if (root == null) {
                //空树
                root = newNode
            } else {
                insertNode(root, newNode)//我们会在这里调用这个方法,然后我们这个node 是从根节点开始的,rootroot,newNode
            }
        }

  7. 遍历也是从根节点开始操作,递归,遍历方法分前序遍历,中序遍历,后续遍历
  8.  
    遍历节点
    var traverse = function(node,callback){
            //这里会一直遍历直到看到node = null   然后会报错所以要判断
            if(node == null)return
                //callback(node,value) 8 2 3 9 前序遍历
            traverse(node.left,callback)
                //callback(node,value)  中序遍历
            traverse(node.right,callback)
                //callback(node,value)   3 2 9 8 后续遍历
            callback(node.value)
        }
        this.traverse = function (callback) {
                traverse(root , callback)
        }

     

     

  9. 查找节点

     

    查找节点
        //1,树还是空的
        //2,树不是空的二叉收搜树
        var min = function (node) {
            if (node == null) return null
            //在这里我们不在使用递归的方式了
            while (node && node.left) {
                node == node.left
            }
            return node.value
        }
        this.min = function (node) {
            return min(root)
        }
    
        var max = function (node) {
            if (node == null) return null
            //在这里我们不在使用递归的方式了
            while (node && node.right) {
                node == node.right
            }
            return node.value
        }
        this.max = function (node) {
            return max(root)
        }
    

  10. 删除节点:最复杂的。删除,移除节点remove(value) 第一种:移除页节点。第二种:移除只有一个子节点的节点。第三种:移除有两个子节点的情况。移除代码实例是重新构建树


    //移除节点                  root 
    var findMimNode = function (node) {
        if (node == null) return null
        while (node && node.left) {
            node = node.left
        }
        return node   //返回最小的子节点
    }
    var rmoverNode = function (node, value) {
        if (node == null) return null
        if (value > node.value) {
            //继续向右查找
            node.right = removeNode(node.right, value)
            return node
        } else if (value < node.value) {
            //继续向左查找
            node.left = removeNode(node.left, value)
            return node
        } else {
            //都相等value ==  node.value
            //那就开始执行删除过程
            if (node.left == null && node.right == null) {
                //满足页节点条件
                node = null
                return node
            }

            //只有一个子节点条件

            if (node.left == null && node.right) {

                return node.right
            } else if(node.right == null && node.left){
                return node.left
            }

            //有两个子节点
            var aux = findMimNode(node.right) //aux 查找到的子节点
            node.value = aux.value
            node.right = removeNode(node.right, aux.value)
            return node

        }

    }
    this.remove = function (value) {
        root = removeNode(root, value)
    }



    var t = new Tree
    t.insert(8)
    t.insert(2)
    t.insert(3)
    t.insert(9)

    t.remove(3)

 

7,图

  1. 我们学的数据结构可以分两大类:第一类是比较基础的数据结构:栈、队列、数组、集合、字典等可能是计算机的低层结构。第二类是比较高级的数据结构:树和图。因为树与图都是做过我们大型的一些程序,是用这种数据结构来做的比如说html就是用树状结构来做的。那这个图结构是可以用来做地图的,另外可以用来做社交网络,所以现在我们用js去实现一个js的图结构。
  2. 问题:(1)如何生成一个图结构。他们之间会有一些二维的结构,连接,单项结构
  3. (2)怎么实现,怎么遍历怎么操作
  4. (3)获取图的一些路径(最短路径)
  5. 图概念,是一种计算机中使用广泛的结构,比如我们常用的社交网络
  6. 有向图
  7. 无向图

 

 

 

 

要理解下面的代码怎么去存储顶点,存储边,以及实现他们的链接的

var Graph = function(){
    //存储顶点
    var vertices = []
    //存储边
    var adjList = {}


    //1.添加顶点
    this.addVertex = function(v){
        vertices.push(v)
        adjList[v] = []
    }
    //2.添加边
    this.addEdge = function(a,b){
        adjList[a].push(b)
        adjList[b].push(a)

    }
    this.print = function(){
        var s = "\n"
        for(var i = 0; i < vertices.length; i++){
            var dingdian = vertices[i]
            s += dingdian + '=>'
            var bian = adjList[dingdian]
            for(var j = 0; j < bian.length; j++){
                s += bian[j]
            }
            s += '\n'
        }
        console.log(s);
    }



}

var g = new Graph
g.addVertex('A')
g.addVertex('B')
g.addVertex('C')
g.addVertex('D')
g.addVertex('E')
g.addVertex('F')
g.addVertex('G')

g.addEdge('A','B')
g.addEdge('A','C')
g.addEdge('A','D')
g.addEdge('B','E')
g.addEdge('E','F')

理解怎么去找最短路径,他们是怎么遍历的(遍历有前,中,后)只是改变了一个callback,很神奇,改变一下回调函数的顺序就有不同的结果。跟递归栈有很大的关系。

 

 


        //初始遍历将 white未发现   grey已发现   black 已探索  v='A'
        this.bfs = function(v,callback){
            var  initColor = function(){
                var color = {}
                for(var i = 0; i < vertices.length; i++ ){
                    color[vertices]= 'white'
                }
                return color
            }
            this.bfs = function(v,callback){
                var color = initColor()
                //color ={ A:'while',B:'while',C:'while'}现在的color是这样的
                var queue = new queue
                queue.enqueue(v)  //对A执行入列操作,假设v是A
                while(!queue.isEmpty()){
                    //首先就是A出列
                    var now = queue.dequeue()  //继续取元素
                    var bian = adjList[now] 
                    //通过遍历for循环去获取它的边缘
                    for(var i = 0; i < bian.length; i++){
                        var w = bian[i]
                        if(color[w] === 'white'){   //w呢是遍历到这个边缘w这个b,然后判断
                            //未发现的全部入列,并且标志为已发现
                            color[w] = 'grey'  //然后将颜色标志灰色
                            queue.enqueue(w)   
                        }
                    }
                    color[now] = 'black'
                    if(callback){
                        callback(now)
                    }
                }
            }
        }

    }

找最近的路径方法特别简单,只要不停的查找回溯点就可以了

 //广度优先算法
    //d 距离
    //pred 回溯点

    //找最短路径
    this.bfs = function (v, callback) {
        var initColor = function () {
            var color = {}
            for (var i = 0; i < vertices.length; i++) {
                color[vertices] = 'white'
            }
            return color
        }
        this.BFS = function (v, callback) {
            var color = initColor()
            //color ={ A:'while',B:'while',C:'while'}现在的color是这样的
            var queue = new queue
            queue.enqueue(v)
            var d = {}
            var pred = {}
            for (var i = 0; i < vertices.length; i++) {
                d[vertices[i]] = 0
                pred[vertices[i]] = null
            }
            while (!queue.isEmpty()) {
                //首先就是A出列
                var now = queue.dequeue()
                var bian = adjList[now]
                //通过遍历for循环去获取它的边缘
                for (var i = 0; i < bian.length; i++) {
                    var w = bian[i]
                    if (color[w] === 'white') {   //w呢是遍历到这个边缘w这个b,然后判断
                        //未发现的全部入列,并且标志为已发现
                        color[w] = 'grey'  //然后将颜色标志灰色
                        //设置回溯点
                        pred[w] = null    //意思pred['B']='A'
                        d[w] = d[now] + 1
                        queue.enqueue(w)
                    }
                }
                color[now] = 'black'
                if (callback) {
                    callback(now)
                }
            }
            return {
                pred: pred,
                d: d
            }
        }
    }

    //广度的优先算法对于一种能解决问题,能保证每个点的回溯点是最短的。
    //添加新的路径
    g.addEdge('D','F')
    //form....to..意思是从哪里来到哪里去
    var zuiduan = function (from,to){
        var v = to ;//设置当前
        vhile(v !== from){
            path.push(v)
            v = s.pred[v]

        }
        path.push(v)

        var str = ''
        while(!path.isEmpty()){
            str += path.pop() + '-'
        }
        str = str.slice(0,str.length-1)

        console.log(str);  //F点的回溯点事B
    }



    zuiduan('A','F')

 

 在这个图结构算法,我们还剩一个深度优先算法。

 

 

很像一个数结构的,树,递归,。如果用到递归一定要用到辅助函数

总结:广度优先算法是它天然可以去处理一个最短的路径

深度优先算法是它遍历的时候可以探索到最深的一个图的最深点,相当于一个变形的树状结构(因为用了一个递归的东西

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值