[ JavaScript ] 数据结构与算法 —— 链表

news/2024/6/18 7:16:13 标签: 数据结构与算法, javascript

本篇主要有三部分

  • 什么是链表
  • 链表的实现
  • 链表的变种

源码地址:https://github.com/yhtx1997/S...

另外,今天2019年2月18日上午发现 2048-vue 版,代码版本不对,且最新版本遗失,无奈只得重新修复了下
2048-vue地址: https://github.com/yhtx1997/S...

什么是链表

链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个
元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。
相对于传统的数组,链表的一个好处在于,添加或移除元素的时候不需要移动其他元素。然
而,链表需要使用指针,因此实现链表时需要额外注意。数组的另一个细节是可以直接访问任何
位置的任何元素,而要想访问链表中间的一个元素,需要从起点(表头)开始迭代列表直到找到
所需的元素。
如下图:
1.png
注:其中 00 06 10 12 18 为假定在内存中的地址

我将已经做好的链表存入数据,然后在控制台打印出来是这样的:
TIM截图20190218164943.png

它看起来就像是这样的,一层套一层

0.png

其实应该是下面这样,类似于栓狗的铁链

3.png

链表的实现

链表功能

  • 添加元素
  • 获取指定位置元素
  • 在指定位置插入元素
  • 移除指定位置的元素
  • 返回指定元素的位置
  • 移除指定元素
  • 是否为空
  • 长度
  • 获取表头
  • 清空链表
  • 转换为字符串输出
// 链表元素
class Node {
    constructor(element) {
        this.element = element; // 元素
        this.next = undefined; // 指向下一个元素
    }
}
class LinkedList {
    // 构造函数声明一些全局变量
    constructor(){
        this.count = 0; // 长度
        this.head = undefined; // 第一个元素
    }
    // 添加元素
    push(element) {
        
    }
    // 获取指定位置元素
    getElementAt(index) {
        
    }
    // 在指定位置插入元素
    insert(element, index) {
        
    }
    // 移除指定位置的元素
    removeAt(index) {
    
    }
    // 返回指定元素的位置
    indexOf(element) {
        
    }
    // 移除指定元素
    remove(element) {
        
    }
    // 是否为空
    isEmpty() {
        
    }
    // 长度
    size() {
        
    }
    // 获取表头
    getHead() {
       
    }
    // 清空链表
    clear() {
        
    }
    // 转换为字符串输出
    toString() {
        
    }
}

代码实现

class LinkedList {
    // 构造函数声明一些全局变量
    constructor(){
        this.count = 0; // 长度
        this.head = undefined; // 第一个元素
    }
    // 添加元素
    push(element) {
        const node = new Node(element);
        if (this.head === undefined) {
            this.head = node;
        } else {
            let current = this.head;
            while (current.next !== undefined) {
                current = current.next;
            }
            current.next = node;
        }
        this.count++;
    }
    // 获取指定位置元素
    getElementAt(index) {
        // 判断不是空链表
        if (this.isEmpty() || index > this.count || index < 0) { 
            // 非空才能继续处理
            // 判断不大于最大长度,不小于最小长度(0)
            return undefined;
        }
        // 循环找到元素
        let current = this.head;
        for (let i = 0; i < index; i++){
            current = current.next;
        }
        return current;// 返回找到的元素
    }
    // 在指定位置插入元素
    insert(element, index) {
        // 创建一个元素
        let current = new Node(element);
        // 首先确定是不是在首位置插入
        if (index === 0){
            current.next = this.head;
            this.head = current;
        } else {
            // 找到指定位置前一个元素
            let previous = this.getElementAt(index - 1);
            // 将前一个元素的 next 赋值给插入元素的 next
            current.next = previous.next;
            // 将插入元素的 node 赋值给前一个元素的 next
            previous.next = current;
        }
        this.count++;
    }
    // 移除指定位置的元素
    removeAt(index) {
        let current = this.head;
        if (index === 0){
            this.head = current.next;
        } else {
            // 找到这个元素和这个元素之前的元素
            let previous = this.getElementAt(index - 1);
            current = previous.next;
            // 将这个元素的 next 赋值给这个元素之前元素的 next
            previous.next = current.next;
        }
        this.count--;
        // 返回要移除的元素
        return current.element;
    }
    // 返回指定元素的位置
    indexOf(element) {
        // 从头开始找
        let current = this.head;
        // 不超过最大长度
        for (let i = 0; i < this.size() && current != null; i++){
            if (current.element === element){ // 找到相等的就返回下标
                return i;
            }
            current = current.next;
        }
        return -1;
    }
    // 移除指定元素
    remove(element) {
        // 获取指定元素位置
        let index = this.indexOf(element);
        // 移除指定位置元素
        return this.removeAt(index);
    }
    // 是否为空
    isEmpty() {
        return this.size() === 0;
    }
    // 长度
    size() {
        return this.count;
    }
    // 获取表头
    getHead() {
        return this.head;
    }
    // 清空链表
    clear() {
        this.head = undefined;
        this.count = 0;
    }
    // 转换为字符串输出
    toString() {
        if (this.head == null) {
            return '';
        }
        let objString = `${this.head.element}`;
        let current = this.head.next;
        for (let i = 1; i < this.size() && current != null; i++) {
            objString = `${objString},${current.element}`;
            current = current.next;
        }
        return objString;
    }
}
let a = new LinkedList();
a.push('a');
a.push('b');
a.push('c');
a.push('d');
a.push('e');
a.push('f');
a.push('h');
a.push('i');
a.push('j');
a.push('k');
a.push('l');
a.push('m');
a.push('n');
a.push('o');
a.push('p');
a.push('q');
a.remove('a');
a.insert('a',1);
console.log(a);

插入元素图解:

现在有狗链两节,我要在中间加一节

4.png

先把两节分开,

5.png

然后把前边的尾部与要加的头部相连,然后把要加的尾部与后边的头部相连

0 连 xx , xx 连 1

6.png

链表的变种

双向链表

我们已经知道链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成,双向链表除了这个基本特性,每个元素还包含一个指向前一个元素的引用,如图所示:

TIM截图20190219171236.png

循环链表

循环链表就是链表的最后一个指向下一个元素的引用指向了第一个元素,使其成为循环链表

双向循环链表

双向循环链表就是双向链表的第一个元素指向前一个的引用指向了最后一个元素,而最后一个元素指向下一个元素的引用指向了第一个元素,如图所示:
TIM截图20190219171514.png


http://www.niftyadmin.cn/n/629185.html

相关文章

做自适应网站专业乐云seo_【图文】自适应网站公司十年乐云seo

自适应网站公司十年乐云seo网站不同时期的SEO优化策略不同&#xff0c;按照每个时期需求不一样做不同的优化能让排名有更好的效果。那么到底怎么区分网站的不同时期以及怎么做优化呢&#xff1f;网站排名前期&#xff1a;SEO优化排名前期也就是网站从上线到排名进入前20名这个时…

matlab 定义全局变量_暂态稳定性 | 发电机摇摆曲线δ-t计算 | matlab程序

《MATLAB/Simulink电力系统建模与仿真》第2版p125简单系统&#xff0c;短路故障&#xff08;II段&#xff09;发电机摇摆曲线δ-t&#xff08;转子运动方程——两个一阶非线性常微分方程&#xff09;&#xff1a;已知切除故障时间&#xff08;III段&#xff09;&#xff0c;求δ…

微信小程序实现红包雨

前言话不多少先上效果,引入很简单&#xff0c;将/components/s-packetrain/index放到你的组件文件夹中直接引用就可以了。首先你要先在页面引入组件index.json 引用组件{ "navigationBarTitleText": "红包雨", "usingComponents": { "…

dbf在excel里更改后在gis中乱码_软件技巧如何在ARCMAP里标注文件特征信息

本文为工作室原创作品&#xff0c;如需转载请联系主页君在OSM下载的数据里&#xff0c;打开他们的属性表&#xff0c;里面往往有非常多的数据信息&#xff0c;例如道路的等级&#xff0c;道路名称&#xff0c;甚至含有道路的长度。当你想直观的体现在总图上时候&#xff0c;就可…

python row函数_Python第16课:函数的定义和调用

如何用最浅显的语言&#xff0c;给中小学生讲Python&#xff0c;是我一直在努力并实践的问题。——华丽老师课程贴士变量名、函数名等&#xff0c;这些名字除了要满足命名规则&#xff0c;还要做到“见名知意”&#xff0c;这是增加代码可读性的基础。满足命名规则很简单&#…

23种设计模式之适配器模式

23种设计模式总篇&#xff1a;&#xff1a;https://chenmingyu.top/categories/设计模式/ 适配器模式 适配器模式属于结构型模式,又叫包装模式 定义&#xff1a; 把一个类的接口变换成客户端所期待的另一种接口&#xff0c;从而使原本接口不匹配而无法一起工作的两个类能够在一…

aws beanstalk mysql_AWS CloudFormation与BeanStalk的联系与区别

关注过云计算的人应该都知道AWS是什么&#xff1f;AWS CloudFormation作为亚马逊的一项服务肯定是有其存在的价值的&#xff01;CloudFormation的中文的意思是“云编排”&#xff0c;在我看来“编排”就 是整合亚马逊云资源或者服务的一种方式&#xff0c;是相对于AWS底层服务的…

PTA编程总结3

题目7-1 抓老鼠啊~亏了还是赚了&#xff1f; 某地老鼠成灾&#xff0c;现悬赏抓老鼠&#xff0c;每抓到一只奖励10元&#xff0c;于是开始跟老鼠斗智斗勇&#xff1a;每天在墙角可选择以下三个操作&#xff1a;放置一个带有一块奶酪的捕鼠夹(T)&#xff0c;或者放置一块奶酪(C…