你需要知道的数据结构

我又来了学习算法了,距离看完初级入门<<我的第一本算法书>>已经过去了小半年,因此,再次从数据结构入手,这一次,我相信光~

不定时更新,如有错误,还请指正。

数组

查询:O(1)
增删:O(n)

从 Chrome v8 源码看,JSArray 继承自 JSObject,且有两种存储模式 FastElements 和 SlowElements。

  • FastElements:快数组存储结构 FixedArray,开辟一段连续的内存,直接使用索引定位,会根据申请的容量进行动态扩容减容。
  • SlowElements:慢数组存储结构 HashTable,不需要连续的内存,但是需要维护一个额外的哈希表,性能相对较差。

转换:

/* -------------------------- 快 -> 慢 -------------------------- */
// 1. 加入索引值 index 与当前容量 capacity 大小的差值大于 1024
// 2. 新容量是扩容后容量的 3 倍之多时'
let arr = [1, 2, 3];
arr[2000] = 4;

/* -------------------------- 慢 -> 快 -------------------------- */
// 慢数组的元素可以存放在快数组中且长度在Smi之间且仅节省50%的空间

动态扩容:

// 扩容算法 capacity + capacity/2 + 16
let arr = [1, 2, 3, 4];
arr.push(5);
// 4 + 2 + 16 = 22
// ps:数组的 push 使⽤汇编实现的, pop 使⽤ c++ 实现的

链表

在内存中分散存储,前一个节点的指针指向下一个节点的内存地址。可以衍生出循环链表、双向链表

查询:O(n)
增删:O(1)

单链表模拟实现:
function LinkedList() {
    let Node = function (element) {
        this.element = element;
        this.next = null;
    };
    // 如同竹子一样,可以把链表也是一节一节的,每一节就是一个node,通过next连接,从head开始,长度也随之增长
    let head = null;
    let length = 0;

    this.getList = function () {
        return head;
    };
    this.size = function () {
        return length;
    };
    // 末尾加入
    this.append = function (element) {
        let node = new Node(element),
            p = head;
        if (!p) {
            head = node;
        } else {
            // 找到最后一个元素,边界条件: p.next === null
            while (p.next) {
                p = p.next;
            }
            p.next = node;
        }
        length += 1;
    };
    this.search = function (element) {
        let p = head;
        if (!p) return false;
        // 对每一个指针进行遍历, 直到最后一个null为止:即 p === null
        while (p) {
            if (p.element === element) return true;
            p = p.next;
        }
        return false;
    };
    this.insert = function (position, element) {
        let node = new Node(element);
        if (position < 0 || position > length) return null;
        let prev = head,
            curr = head,
            index = 0;
        if (position == 0) {
            node.next = head;
            head = node;
        } else {
            // 找出要插入位置的前后元素
            while (index < position) {
                prev = curr;
                curr = curr.next;
                index++;
            }
            prev.next = node;
            node.next = curr;
        }
        length += 1;
    };
    // 删除 找到删除元素的位置,把前一个元素的next指向后一个元素
    this.remove = function (element) {
        if (!head) return;
        let p = head,
            prev = head;
        while (p) {
            if (p.element === elment) {
                p = p.next;
                prev.next = p;
            }
            prev = p;
            p = p.next;
        }
        length -= 1;
    };
}

不仅仅是链表,我将在所有需要指针的地方默认使用 p 来代表指针(pointer)

双链表模拟实现:
// 对比单链表其实就是有两个指针,一个从前往后,一个从后往前
function DoubleLinkedList() {
    let Node = function (element) {
        this.element = element;
        // 前驱指针
        this.prev = null;
        // 后驱指针
        this.next = null;
    };
    // 头尾
    let head = null,
        tail = null,
        length = 0;
    // 主要实现一下增删
    this.insert = function (position, element) {
        if (position < 0 || position > length) return null;
        let node = new Node(element);
        let prev = head,
            curr = head,
            index = 0;
        // 首位
        if (position == 0) {
            // 首位为空
            if (!head) {
                head = node;
                tail = node;
            } else {
                node.next = head;
                head.prev = node;
                head = node; // head指向新的node
            }
        } else if (position === length) {
            // 尾节点
            curr = tail;
            curr.next = node;
            node.prev = curr;
            tail = node;
        } else {
            // 定位到插入位置的元素及后一个元素
            while (index < position) {
                prev = curr;
                curr = curr.next;
                index++;
            }
            prev.next = node;
            nodex.next = curr;
            curr.prev = node;
            node.prev = prev;
        }
        length += 1;
    };
    this.remove = function (position) {
        if (position < 0 || position > length) return false;
        let prev = head,
            curr = head,
            index = 0;

        if (position === 0) {
            if (length === 1) {
                head = null;
                tail = null;
            } else {
                head = head.next;
                head.prev = null;
            }
        } else if (position === length - 1) {
            // 找到删除元素和前一个元素
            while (index < position) {
                prev = curr;
                curr = curr.next;
                index++;
            }
            prev.next = curr.next;
            curr.next.prev = prev;
        }
        length -= 1;
    };
}
循环链表
function CircleLinkedList() {
    let Node = function (element) {
        this.element = element;
        this.next = null;
    };
    let head = null;
    let length = 0;
    this.insert = function (position, element) {
        if (position < 0 || position > length) return null;
        let node = new Node(element);
        let prev = head,
            curr = node,
            index = 0;
        if (position === 0) {
            // 找到第一个
            while (index++ < length) {
                prev = curr;
                curr = curr.next;
            }
            prev.next = ndoe;
            node.next = curr;
        } else {
            while (index++ < position) {
                prev = curr;
                curr = curr.next;
            }
            prev.next = ndoe;
            node.next = curr;
        }
        length += 1;
    };
}```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yokiizx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值