数据结构与算法

171 阅读4分钟

数据结构

数据结构分物理结构和逻辑结构

物理数据结构

数据结构的存储形式有两种:顺序存储和链式存储

逻辑结构

  1. 集合结构 数据间同属一个集合并无其它关系
  2. 线性结构 数据之间是一对一的关系
  3. 图形结构 数据间是多对多的关系
  4. 树形结构 数据之间存在一对多的层次关系

队列

先进先出

队列

//现实中典型例子的就是叫号了
const currentNumber = document.getElementById('currentNumber')
const callNumber = document.getElementById('callNumber')
const getNumber = document.getElementById('getNumber')
const newNumber = document.getElementById('newNumber')
const queueList = document.getElementById('queueList')

let number = 0
let queue = []
currentNumber.innerText = '还未开始叫号'
getNumber.onclick = () => {
    number += 1
    queue.push(number)
    newNumber.innerText = `${number},前面还有${queue.length - 1}人`//可优化
    queueList.innerText = queue.toString()
}
callNumber.onclick = () => {
    if (queue.length < 1) {
        alert('目前没有用户')
    } else {
        let current = queue.shift()
        currentNumber.innerText = `请${current}号就餐`
        queueList.innerText = queue.toString()
    }
}

先进后出,顺序存储

//现实中的例子就是电梯了,这里用函数压栈,弹栈的方式解释
function f1(){let a = 1 return a+f2()}
function f2(){let b = 2 return b+f3()}
function f3(){let b = 3 return b}
f1()

还是看图吧

栈

链表

对象与对象之间的指引关系(函数也是对象),无需存储

//通过链表实现节点的增删改查
//创建节点
const createNode = (value) => {
    return {
        data: value,
        nextNode: null
    }
}
//添加节点
const appendNode = (node, value) => {
    let lastNode = node
    while (lastNode.nextNode) {
        lastNode = lastNode.nextNode
    }
    lastNode.nextNode = createNode(value)
    return lastNode.nextNode
}
//删除节点
const removeNode = (list, node) => {
    let lastNode = list
    let parentNode = node
    if (!node) { return alert('节点为空') }
    while (lastNode !== node) {
        parentNode = lastNode
        lastNode = lastNode.nextNode
    }
    if (parentNode === lastNode) {
        parentNode = lastNode.nextNode
        return parentNode
    } else {
        parentNode.nextNode = lastNode.nextNode
        return lastNode
    }
}
//遍历节点
const travel = (list, fn) => {
    let lastNode = list
    fn(lastNode)
    while (lastNode.nextNode) {
        lastNode = lastNode.nextNode
        fn(lastNode)
    }
}
let list = createNode(10)
let node1 = appendNode(list, 20)
let node2 = appendNode(list, 30)
let node3 = appendNode(list, 40)
let node4 = appendNode(list, 50)
let list2 = removeNode(list, list)
console.log(list2)
travel(list, (node) => console.log(node.data))

hash表

key 对应value,key是唯一的,不重复的
也叫散列函数,散列映射
关于解决碰撞(冲突)最常用的是除留余数法
js中的对象是模拟hash表实现的

树形结构

树形结构我们前端应该很熟悉,dom树就是这种类型
一对多的关系,链表的升级版,下面用一个小例子实现节点的增删改查

//创建节点
const createNode = (value, parentNode) => {
    return {
        node: value,
        children: null,
        parent: parentNode || null
    }
}
//添加节点
const appendChildren = (tree, value) => {
    let newNode = createNode(value, tree)
    tree.children = tree.children || []
    tree.children.push(newNode)
    return newNode
}
//删除节点
const removeChildren = (tree, node) => {
    if (tree == node) {
        alert('你删根节点还用这么费劲?')
    }
    for (let i in tree.children) {
        if (tree.children[i] !== node) {
            removeChildren(tree.children[i], node)
        } else {
            tree.children.splice(i, 1)
        }
    }
    return tree
}
//遍历节点
const travel = (node, fn) => {
    fn(node)
    for (let i in node.children) {
        if (node.children[i]) {
            travel(node.children[i], fn)
        }
    }
}
let tree = createNode(10)
let node2 = appendChildren(tree, 20)
let node3 = appendChildren(tree, 30)
let node2_1 = appendChildren(node2, 201)
let node2_2 = appendChildren(node2, 202)
let node3_2 = appendChildren(node3, 302)
let node3_3 = appendChildren(node3, 303)
removeChildren(node3, node3_2)
travel(tree, (tree) => console.log(tree.node))

什么是算法

将一个小故事吧,高斯算法
高斯小时候非常淘气,一次数学课上,老师为了让他们安静下来,给他们列了一道很难的算式,让他们一个小时内算出1+2+3+4+5+6+……+100的得数。全班只有高斯用了不到20分钟给出了答案,因为他想到了用(1+100)+(2+99)+(3+98)……+(50+51)……一共有50个101,所以50×101就是1加到一百的得数。后来人们把这种简便算法称作高斯算法。

//我们重复计算1+2+3+4+5....100
let number = 1
for (let i = 1; i < 100; i++) {
    console.log(i)
    number += i + 1
}//这种算法 随着数字的增大,计算次数也会增加

console.log(number)
//高斯算法发现每个数之间的规律 1+100 =101 2+99=101 3+98 =101
result = (100 / 2) * 101//用这种方法 无论数字有多大,我们只用计算一次
console.log(result)
//从事物之间的关系找到规律,找到最合适的算法

算法的五个基本特征

输入 具有零个或多个输入
输出 具有一个或多个输出
有穷性 自动结束,不会无限循环
可行性 每一个步骤都是可行的
确定性 每一个步骤都有确定的含义,不会出现二义性