前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

代码逐风
• 阅读 4768

前言

上一次我们讲到了数据结构:栈和队列,并对他们的运用做了一些介绍和案例实践;我们也讲到了怎么简单的实现一个四则运算、怎么去判断标签是否闭合完全等等,anyway,今天接着和大家介绍一些数据结构:
上一篇:前端算法系列之一:时间复杂度、空间复杂度以及数据结构栈、队列的实现

链表

链表是一种怎么样的结构呢?链表就是一种可以把数据串联起来的结构,每个元素会有指向下一个元素的指针(末尾的没有普通链表),就像现实世界中的火车一样一节一节的串联起来;链表根据自身的指针指向又可以分为:单向链表、双向链表、循环链表;

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

链表首先会有一个表头,表头作为起始的指针,然后每一个元素我们称作为节点(node);每个节点有一个指向下一个节点的指针(next),直到链表的末尾指针会指向undefined;

链表的实现

1、节点

节点的创建和定义;每个节点会有一个保存自己数据的属性(element),然后有一个指针(next)

export class Node {
    constructor(element, next = null) {
        this.element = element;
        this.next = next;
    }
}

2、链表的api

getElementAt(position): 获取某个位置的元素

append(element): 向链表末尾中添加元素

removeAt(idx): 移除某个元素

insert(element, position = 0, dir = 'before'): 向指定位置添加元素

insertAfter(element, position): 向指定的位置后面添加元素

size(): 链表的长度

remove(): 删除链表末端元素

removeAll(): 删除整个链表

isEmpty(): 检查链表是否为空

import { defaultEquals } from "../util.js";
import { Node } from './Node.js'

export default class LinkedList {
    constructor(equalsFn = defaultEquals) {
        this.count = 0;
        this.head = null;
        this.equalsFn = equalsFn;
    }
    getElementAt(position) {
        if(position >= 0 && position <= this.count) {
            let node = this.head;
            for (let i = 0; i < position && !!node; i++) {
                node = node.next;
            }
            return node;
        }
        return undefined;
    }

    insertAfter(element, position) {
        return this.insert(element, position, 'after');
    }
    size() {
        return this.count;
    }
    remove() {
        return this.removeAt(this.size() - 1);
    }
    removeAll() {
        this.count = 0;
        this.head = null;
    }
    isEmpty() {
        return this.size() === 0;
    }
    getHead() {
        return this.head;
    }
}

3、链表末尾添加一个元素append;

    append(element) {
        const node = new Node(element);
        let current = this.head;
        if(current == null) {
            this.head = node;
        } else {
            current = this.head;
            while (current.next !=  null) {
                current = current.next;
            }
            current.next = node
        }
        this.count++;
        return element;
    }

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

4、插入一个元素

    insert(element, position = 0, dir = 'before') {
        if (element === undefined) {
             throw Error('缺少需要插入的元素');
             return;
        }
        if (position >= this.count) {
            return this.append(element);
        }
        const node = new Node(element);
        const targetNode = dir === 'before' ? this.getElementAt(position - 1) : this.getElementAt(position);
        if (!targetNode) {
            let prev = this.head;
            this.head = node;
            node.next = prev;
        } else {
            let next;
            next = targetNode.next
            targetNode.next = node;
            node.next = next;
        }
        this.count++;
        return element;
    }

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

5、删除一个元素

removeAt(idx) {
        if (idx >= 0 && idx < this.count) {
            let current = this.head;
            if (idx === 0) {
                this.head = current.next;
                current.next = null;
            } else {
                let prev = this.getElementAt(idx - 1);
                current = prev.next;
                prev.next = current.next;
            }
            this.count--;
            return current.element;
        }
        return undefined;
    }

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

6、双向链表

单向链表元素指向都是一个方向的,也只能被单向递归搜索,而双向链表不仅仅有指向下一个元素的指针同时具有指向上一个元素的指针;

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

import LinkedList from "./LinkedList";
import {defaultEquals} from "../util";
import { DoubleNode } from "./DoubleNode";

export default class DoubleLinkedList extends LinkedList{
    constructor(equalIsFn = defaultEquals){
        super(equalIsFn);
        this.tail = null;// 队列尾部
    }
    getElementAt(position) {
        if(position >= 0 && position <= this.count) {
            if (position > this.count/2) {
                let cur = this.tail;
                for (let i = this.count - 1; i > position; i--){
                    cur = cur.prev;
                }
                return cur;
            } else {
                return super.getElementAt(position)
            }
        }
        return undefined;
    }
    removeAll() {
        super.removeAll();
        this.tail = null;
    }
    removeAt(position) {
        if (position >= 0 && position < this.count) {
            let cur = this.getElementAt(position);
            if(position === 0) {
                this.head = cur.next;
                cur.next = null;
                this.prev = null;
            } else if (position === this.count - 1) {
                this.tail = cur.prev;
                this.tail.next = null;
                cur.prev = null;
            } else {
                let prev = cur.prev;
                let next = cur.next;
                prev.next = next;
                next.prev = prev;
                cur.prev = null;
                cur.next = null;
            }
            this.count--;
            return cur.element;
        }
        return undefined;
    }
}

队列末尾插入元素(append)

双向链表插入元素和单向比较类似,不同的是双向不仅要链接他的下级还得关联他的前一级;

    append(element) {
        const node = new DoubleNode(element);
        if (!this.tail) {
            this.head = node;
            this.tail = node;
        } else {
            let cur = this.tail;
            cur.next = node;
            node.prev = cur;
            this.tail = node;
        }
        this.count++;
        return element;
    }

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

中间某个位置插入元素

insert(element, position = 0, dir = 'before'){
        if (element === undefined) {
            throw Error('缺少需要插入的元素');
            return;
        }
        if (position >= this.count) {
            return this.append(element);
        }
        const node = new DoubleNode(element);
        let cur;
        const targetNode = dir === 'before' ? this.getElementAt(position - 1) : this.getElementAt(position);
        if (!targetNode) {
            cur = this.head;
            node.next = cur;
            cur.prev = node;
            this.head = node;
        } else {
            let next;
            next = targetNode.next
            targetNode.next = node;
            node.prev = targetNode;
            node.next = next;
            next.prev = node;
        }
        this.count++;
        return element;
    }

前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

移除某个元素也是上述相同,修改节点的前后指针就可以了,这里不再赘述,详情看源码

https://github.com/JasonCloud/DataStructuresAndAlgorithms

闭环链表

闭环链表也称环,是一个闭合的结构,尾部会指向头部
前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

有序链表

有序链表就是在append元素的时候进行排序加入从而得到一个有顺序的链表,比较函数可以根据实例化的时候传入比较函数equalIsFn;

获取第一手信息请关注我的专栏或者关注公众号
前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
4年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
4年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
深度学习 深度学习
8个月前
链表栈实现指南:从基础到实践
一、简介和特点链表栈是一种使用链表实现的栈数据结构,遵循后进先出(LIFO)原则。本文实现的链表栈通过动态内存分配节点,避免了数组实现的固定大小限制。‌主要特点‌:1.动态大小:无需预先分配固定空间2.高效操作:入栈和出栈都是O(1)时间复杂度3.内存效率
代码逐风
代码逐风
Lv1
南朝四百八十寺,多少楼台烟雨中。
文章
3
粉丝
0
获赞
0