JavaScript数据结构与算法 — 单向链表

目录

1、链表的定义

 2、链表结构的实现

2.1、单链表常见方法和操作

2.2、单链表的代码实现

3、总结


1、链表的定义

链表存储的是有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称为指针或链接)组成。

相对于传统的数组,链表的一个好处在于,添加或者移除元素的时候不需要移动其他元素。然而,链表需要使用指针,因此实现链表时需要额外注意。在数组中,我们可以直接访问任何位置的任何元素,而要向访问链表中间的一个元素,则需要从起点(表头)开始迭代链表直到找到所需的元素。

(学习JavaScript数据结构与算法(第三版))

 2、链表结构的实现

2.1、单链表常见方法和操作

  • append(element) 向链表尾部添加一个新的项。

  • insert(position, element) 向链表的特定位置插入一个新的项。

  • get(position) 获取对应位置的元素。

  • indexOf(element) 返回元素在链表中的索引。如果链表中没有该元素就返回-1。

  • update(position, element) 修改某个位置的元素。

  • removeAt(position) 从链表的特定位置移除一项。

  • remove(element) 从链表中移除一项。

  • isEmpty() 如果链表中不包含任何元素,返回 trun,如果链表长度大于 0 则返回 false。

  • size() 返回链表包含的元素个数,与数组的 length 属性类似。

  • toString() 由于链表项使用了 Node 类,就需要重写继承自 JavaScript 对象默认的 toString 方法,让其只输出元素的值。

2.2、单链表的代码实现

        // 首先定义链表的每个节点,每个节点用对象来表示
        class Node {
            constructor(data) {
                // 每个链表的数据
                this.data = data;
                // 每个节点的下一个链表的指针
                this.next = null;
            }
        }
        class LinkList {
            constructor() {
                this.head = null;//定义链表的头节点,也就是指向第一个节点的指针
                this.length = 0;//链表元素的个数,也就是链表的长度
            }
            append(data) {
                if (this.length == 0) {
                    // 链表的第一个节点,直接添加
                    let newnode = new Node(data);
                    this.head = newnode;
                } else {
                    let newnode = new Node(data);
                    let flag = this.head;
                    // 通过while循环找到当前链表的最后一个节点
                    while (flag.next) {
                        flag = flag.next;
                    }
                    flag.next = newnode;
                }
                this.length++;
            }

            insert(position, data) {
                let newnode = new Node(data);
                let flag = this.head;
                // 有两种情况,第一种是直接插入第一个的位置,第二种插入第一个后面位置
                if (position == 1) {
                    newnode.next = this.head;
                    this.head = newnode;
                    this.length++;
                } else {
                    //通过循环找到插入的位置,由于是指向插入操作,使用我们要找到插入位置的前一个节点
                    for (let i = 1; i < position - 1; i++) {
                        flag = flag.next;
                    }
                    newnode.next = flag.next;
                    flag.next = newnode;
                    this.length++;
                }
            }

            get(position) {
                // 这里也有两种情况,如果找第一个直接返回头节点,如果不是就循环查找
                let flag = this.head;
                if (position == 1) {
                    return flag;
                } else {
                    // 循环找到具体的位置
                    for (let i = 1; i < position; i++) {
                        flag = flag.next;
                    }
                    return flag;
                }
            }

            indexof(data) {
                // 我这里是想的前面插入操作有个头节点,所以要分情况,但实际上可以不分情况进行循环
                let flag = this.head;
                if (this.head.data == data) {
                    return 1;
                } else {
                    // 思想和上面一样
                    for (let i = 1; i < this.length; i++) {
                        flag = flag.next;
                        if (flag.data == data) {
                            return i + 1;
                        }
                    }
                    return -1;
                }
            }

            updata(position, data) {
                let flag = this.head;
                if (position == 1) {
                    flag.data = data;
                } else {
                    for (let i = 1; i < position; i++) {
                        flag = flag.next;
                    }
                    flag.data = data;
                }
            }

            removeAt(position) {
                let flag = this.head;
                if (position == 1) {
                    this.head = flag.next;
                    this.length--;
                } else {
                    for (let i = 1; i < position - 1; i++) {
                        flag = flag.next;
                    }
                    flag.next = flag.next.next;
                    this.length--;
                }
            }

            remove(data) {
                let flag = this.head;
                if (this.head.data == data) {
                    this.head = flag.next;
                    this.length--;
                } else {
                    for (let i = 1; i <= this.length; i++) {
                        flag = flag.next;
                        if (flag.next.data == data) {
                            flag.next = flag.next.next;
                            this.length--;
                            break;
                        }
                    }
                }
            }

            isEnpty() {
                return this.length === 0;
            }

            size() {
                return this.length;
            }

            toString() {
                let flag = this.head;
                let str = '' + flag.data;
                for (let i = 0; i < this.length - 1; i++) {
                    flag = flag.next;
                    str += flag.data;
                }
                return str;
            }
        }

3、总结

记录学习,当个笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值