资讯专栏INFORMATION COLUMN

我对JS链表的简单学习

余学文 / 2310人阅读

摘要:我对链表的学习什么是链表要存储多个元素,数组可能是最常用的数据结构。链表的学习创建一个链表各种方法表示要加入列表的项,它包含一个属性以及一个属性,表示要添加到列表的值,表示指向列表下一个节点项的指针。

我对JS链表的学习 什么是链表

要存储多个元素,数组可能是最常用的数据结构。这种数据结构非常方便,但是有一个缺点:从数组的起点或者中间插入或移除项的成本非常高,因为需要移动元素(比如你插入一个元素后面的所有的元素都移动了“位置”)。

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

相比于数组来说,链表的好处在于添加或者删除元素的时候不需要移动其他元素。但是操作链表需要使用指针。数组的一个优点是可以直接访问任何位置的任何元素,但是要是想访问链表中的某一元素,则是必须从起点开始迭代直到找到目标元素。

链表的学习

创建一个链表

function LinkedList() {
    var Node = function(element) {
        this.element = element;
        this.next = null;
    }

    //各种方法
}

Node表示要加入列表的项,它包含一个element属性以及一个next属性,element表示要添加到列表的值,next表示指向列表下一个节点项的指针。

当一个Node元素被创建时,它的next指针总是null

向链表尾部追加元素

列表为空,添加的是第一个元素。列表不为空,向其追加元素。

要循环访问列表中的所有元素,就需要有一个起点,就是head

this.append = function(element) {
    var node = new Node(element), //传入值创建Node项
        current;

    if(head === null) { //如果为空链表
        head = node; //设置node为head(head为第一个节点的引用)
    } else {
        current = head; //从表头开始
        while(current.next) { 
            //循环列表,找到最后一项(列表最后一个节点的下一个元素始终是null)
            current = current.next;
        }
        //使当前最后一项的指针指向node
        current.next = node;
    }
    length++; //更新列表长度
};

使用append

var list = new LinkedList();
list.append(15);
list.append(10);

从链表移除元素

输入位置,从特定位置移除一个元素

this.removeAt = function(position) {
    if(position > -1 && position < length) { //有效性检测
        var current = head, //用current来循环列表
        previous,
        index = 0;

        if(position === 0) {
            head = current.next; //移除第一个元素,直接把head指向下一个元素
        } else {
            while(index++ < position) { //循环列表找到满足条件的那个元素
                previous = current; //
                current = current.next; //把下一个变量覆给current
            }
            //跳过current,将当前要移除的元素的上一个与下一项直接连接起来。
            previous.next = current.next;
        }
        length --;
        return current.element;
    } else {
        return null;
    }
}

在任意位置插入一个元素

this.insert = function (position, element) {
    if(position >= 0 && position <= length) {
        var node = new Node(element),
            current = head; //通过current从head位置开始迭代
            previous,
            index = 0;

        if(position === 0) { //第一个位置
            node.next = current; //此时current = head,指向head那么node就成了第一个
            head = node; //node指向为head
        } else {
            while (index++ < position ) { //循环迭代到目标位置
                previous = current; 
                current = current.next;
            }

            node.next = current; // node的下一个为current
            previous.next = node; // node的上一个位置为previous
        }
        length++;
        return true;
    } else {
        return false;
    }
}

把LinkedList对象转换成一个字符串。

this.toString = function() {
    var current = head,
        string = "";
    while(current) { //循环访问列表
        string += current.element + (current.next ? "
" : "");
        current = current.next;
    }
    return string; //返回字符串
}

返回元素的位置

this.indexOf = function(element) {
    var current = head,
        index = 0;
    while(current) {
        if(element === current.element) {
            return index; //找到返回当前位置
        }
        index ++;
        current = current.next;
    }
    return -1;    //找不到返回-1
}

输入元素,移除该元素

this.remove = function(element) {
    var index = this.indexOf(element); //得到元素的位置
    return this.removeAt(index); //移除该元素
}

判断是否为空 得到长度 得到第一个元素

this.isEmpty = function () {
    return length === 0;
}

this.size = function () {
    return length;
}

this.getHead = function () {
    return head;
}
双向链表

他和普通链表的区别,在双向链表中,链接是双向的,一个链向下一个元素一个链向上一个元素。在操作双向链表的时候既要像普通链表一样考虑next,也要考虑prev。

双向列表提供了两种迭代列表的方法:从头到尾迭代,或者反过来。

创建一个双向列表

function DoublyLinkedList() {
    var Node = function(element) {
        this.element = element;
        this.next = null;
        this.prev = null; //新指针
    };
    
    var length = 0;
    var head = null;
    var tail = null; //对列表最后一项的引用
    
    //各种方法
}

在任意位置插入一个新元素

this.insert = function(position, element) {
    if(position >= 0 && position <= length) {
        var node = new Node(element),
            current = head,
            previous,
            index = 0;
            
        if(position === 0) { //在第一个位置添加
            if(!head) { //如果head不存在即链表为空
                head = node;
                tail = node;
            } else { //链表不为空
                node.next = current;
                current.prev = node;
                head = node;
            }
        } else if(position === length) { //在最后一个位置添加
            current = tail;
            current.next = node;
            node.prev = current;
            tail = node;
        } else {
            while(index++ < position) { //在列表中间添加
                previous = current; //循环迭代
                current = current.next;
            }
            node.next = current;
            previous.next = node;
            
            current.prev = node;
            node.prev = previous;
        }
        length ++; //更新列表长度
        
        return true;
    } else {
        return false;
    }
}

从任意位置移除元素

this.removeAt = function(position) {
    if(position > -1 && position < length) { //检查越界值
        var current = head,
            previous,
            index = 0;
        if(position === 0) { //第一个位置
            head = current.next;
            
            if(length === 1) { //如果链表只有一项
                tail = null;
            } else { //也就相当于把current.next.prev = null
                head.prev = null;
            }
        } else if(position === length -1) { //最后一项
            current = tail; //tail的引用赋给current变量
            tail = current.prev; //上一项指向tail
            tail.next = null; //最后一项的next都是指向null的
        } else {
            while(index++ < position) { //从中间位置移除
                previous = current;
                current = current.next;
            }
            
            previous.next = current.next; //直接跳过current连接上一项和下一项
            current.next.prev = previous;
        }
        length --;
        return current.element;
    } else {
        return null;
    }
}
循环链表

单向循环链表和链表唯一去别在于:最后一个元素指向下一个元素的指针(tail.next)不是引用null而是指向第一个元素(head)

双向循环链表有指向head的tail.next,也有指向tail的head.prev

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82004.html

相关文章

  • 我对JS散列表的简单学习

    摘要:对散列表的简单学习类也叫类,是类的一种散列表实现方式。键值散列函数散列值形成散列表地址数据键值对相关操作方法创建一个散列表实现一个散列函数,即将码值相加的方法。 对JS散列表的简单学习 HashTable类也叫HashMap类,是Dictionary类的一种散列表实现方式。 散列算法的作用是尽可能快的在数据结构中找到一个值。 在之前的学习中,如果你想要获得数据结构中的一个值,需要遍历整...

    lindroid 评论0 收藏0
  • Leetcode:刷完31道链表题的一点总结

    摘要:既然说到地址空间了就顺带说一下上面环形链表这道题的另一种很的解法吧。介绍完常规操作链表的一些基本知识点后,现在回到快慢指针。   前几天第一次在 Segmentfault 发文—JavaScript:十大排序的算法思路和代码实现,发现大家似乎挺喜欢算法的,所以今天再分享一篇前两个星期写的 Leetcode 刷题总结,希望对大家能有所帮助。   本文首发于我的blog 前言   今天终于...

    DevTalking 评论0 收藏0
  • JS数据结构与算法_链表

    摘要:上一篇数据结构与算法栈队列下一篇数据结构与算法集合字典写在前面说明数据结构与算法系列文章的代码和示例均可在此找到上一篇博客发布以后,仅几天的时间竟然成为了我写博客以来点赞数最多的一篇博客。 上一篇:JS数据结构与算法_栈&队列下一篇:JS数据结构与算法_集合&字典 写在前面 说明:JS数据结构与算法 系列文章的代码和示例均可在此找到 上一篇博客发布以后,仅几天的时间竟然成为了我写博客以...

    NeverSayNever 评论0 收藏0
  • JS数据结构学习链表

    摘要:在存储多个元素时,我们最常用的数据结构可能是数组,究其原因可能是数组访问方便,可以直接通过访问,但是数组也存在一定的缺点,数组的大小是固定,数组在执行插入或者删除的时候成本很高。 在存储多个元素时,我们最常用的数据结构可能是数组,究其原因可能是数组访问方便,可以直接通过[]访问,但是数组也存在一定的缺点,数组的大小是固定,数组在执行插入或者删除的时候成本很高。链表存储的是有序的元素集合...

    XanaHopper 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<