Javascript 实现基础数据结构

Tip

计算机基础不管是什么语言、什么开发岗位都是必须要了解的知识,本文主要是通过 JS 来实现一些常用的数据结构,很简单。

本文插图引用:啊哈!算法 ,由于是总结性文章,所以会不定时地修改并更新,欢迎关注!

Stack 栈

堆栈(stack),也可以直接称为,它是一种后进先出的数据结构,并且限定了只能在一段进行插入和删除操作。

如上图所示,假设我们有一个球桶,并且桶的直径只能允许一个球通过。如果按照 2 1 3 的顺序把球放入桶中,然后要将球从桶中取出,取出的顺序就是 3 1 2,先放入桶中的球被后取出,这就是 插入和删除的原理。

我们接触过的算法书基本也都是用c语言实现这个数据结构,它的特殊之处在于只能允许链接串列或者阵列的一端(top)进行 插入数据(push)和 输出数据(pop)的运算。那么如果要用 JS 来实现它又该怎么操作呢?

// 栈可以用一维数组或连结串列的形式来完成

class Stack {
    constructor() {
        this.data = []
        this.top = 0
    }
    // 入栈
    push() {
        const args = [...arguments]
        args.forEach(arg => this.data[this.top++] = arg)
        return this.top
    }
    // 出栈
    pop() {
        if(this.top === 0) {
            throw new Error('The stack is already empty!')
        }
        const popData = this.data[--this.top]
        this.data = this.data.slice(0, -1)
        return popData
    }
    // 获取栈内元素的个数
    length() {
        return this.top
    }
    //  判断栈是否为空
    isEmpty() {
        return this.top === 0
    }
    // 获取栈顶元素
    goTop() {
        return this.data[this.top-1]
    }
    // 清空栈
    clear() {
        this.top = 0
        return this.data = []
    }
}

通过 面向对象 的思想就可以抽象出一个 的对象,实例化:

const stack = new Stack()

stack.push(1, 2)
stack.push(3, 4, 5)
console.log(stack.data)
// [ 1, 2, 3, 4, 5 ]
console.log(stack.length())
// 5
console.log(stack.goTop())
// 5
console.log(stack.pop())
// 5
console.log(stack.pop())
// 4
console.log(stack.goTop())
// 3
console.log(stack.data)
// [ 1, 2, 3 ]

stack.clear()
console.log(stack.data)
// []

啊哈!算法 描述 的应用时,举了一个求回文数的例子,我们也用 JS 来把它实现一波:

const isPalindrome = function(words) {
    const stack = new Stack()
    let copy = ''
    words = words.toString()

    words.split('').forEach(word => stack.push(word))

    while(stack.length() > 0) {
        copy += stack.pop()
    }
    return copy === words
}

console.log(isPalindrome('123ada321'))
// true
console.log(isPalindrome(1234321))
// true
console.log(isPalindrome('addaw'))
// false

Linked List 链表

在存储一大波数的时候,我们通常使用的是数组,但有时候数组显得不够灵活,比如:有一串已经从小到大排好序的数 2 3 5 8 9 10 18 26 32。现需要往这串数中插入 6 使其得到的新序列仍符合从小到大排列。

如上图所示,如果使用数组来实现的话,则需要将 8 和 8 后面的 数都依次往后挪一位,这样操作显然很耽误时间,如果使用 链表 则会快很多:

链表(Linked List)是一种常见的数据结构。它是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针。和图中一样,如果需要在 8 前面插入一个 6,直接插入就行了,而无需再将 8 及后面的数都依次往后挪一位。

那么问题来了,如何使用 JS 实现 链表呢?还是运用 面向对象 的思想:

// 抽象节点类
function Node(el) {
    this.el = el
    this.next = null
}

// 抽象链表类
class LinkedList {
    constructor() {
        this.head = new Node('head')
    }
    // 查找数据
    find(item) {
        let curr = this.head
        while(curr.el !== item) {
            curr = curr.next
        }
        return curr
    }
    // 查找前一个节点
    findPre(item) {
        if(item === 'head') {
            throw new Error('Now is head!')
        }
        let curr = this.head
        while(curr.next && curr.next.el !== item) {
            curr = curr.next
        }
        return curr
    }
    // 在 item 后插入节点
    insert(newEl, item) {
        let newNode = new Node(newEl)
        let curr = this.find(item)
        newNode.next = curr.next
        curr.next = newNode
    }
    // 删除节点
    remove(item) {
        let pre = this.findPre(item)
        if(pre.next !== null) {
            pre.next = pre.next.next
        }
    }
    // 显示链表中所有元素
    display() {
        let curr = this.head
        while(curr.next !== null) {
            console.log(curr.next.el)
            curr = curr.next
        }
    }
}

实例化:

const list = new LinkedList()
list.insert('0', 'head')
list.insert('1', '0')
list.insert('2', '1')
list.insert('3', '2')
console.log(list.findPre('1'))
// Node { el: '0', next: Node { el: '1', next: Node { el: '2', next: [Object] } } }
list.remove('1')
console.log(list)
// LinkedList { head: Node { el: 'head', next: Node { el: '0', next: [Object] } } }
console.log(list.display())
// 0 2 3

Binary tree 二叉树

二叉树(binary tree)是一种特殊的树。二叉树 的特点是每个结点最多有两个儿子,左边的叫做左儿子,右边的叫做右儿子,或者说每个结点最多有两棵子树。更加严格的递归定义是:二叉树 要么为空,要么由根结点、左子树和右子树组成,而左子树和右子树分别是一棵 二叉树

和前两个例子一样,通过类的抽象来实现 二叉树

// 抽象节点类
function Node(key) {
    this.key = key
    this.left = null
    this.right = null
}
// 插入节点的方法
const insertNode = function(node, newNode) {
    if (newNode.key < node.key) {
        if (node.left === null) {
            node.left = newNode
        } else {
            insertNode(node.left, newNode)
        }
    } else {
        if (node.right === null) {
            node.right = newNode
        } else {
            insertNode(node.right, newNode)
        }
    }
} 
// 抽象二叉树
class BinaryTree {
    constructor() {
        this.root = null
    }
    insert(key) {
        let newNode = new Node(key)
        if(this.root === null) {
            this.root = newNode
        } else {
            insertNode(this.root, newNode)
        }
    }
}

实例化测试一波:

const data = [8, 3, 10, 1, 6, 14, 4, 7, 13]

// 实例化二叉树的数据结构
const binaryTree = new BinaryTree()
// 遍历数据并插入
data.forEach(item => binaryTree.insert(item))
// 打印结果
console.log(binaryTree.root)
/*
Node {
  key: 8,
  left:
   Node {
     key: 3,
     left: Node { key: 1, left: null, right: null },
     right: Node { key: 6, left: [Object], right: [Object] } },
  right:
   Node {
     key: 10,
     left: null,
     right: Node { key: 14, left: [Object], right: null } } }
*/

总结

算法和数据结构是非常重要的一环,之后也会慢慢总结更新,欢迎关注!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容