JavaScript数据结构与算法 -- 双向链表

1.单项链表简介和缺点

  • 只能从头遍历到尾或者从尾遍历到头(一般从头遍历到尾)。
  • 也就是链表相连的过程是单向的。
  • 实现的原理就是上一个链表有一个指向下一个链表的引用。
  • 我们可以很轻松的到下一个节点,但是回到前一个节点是很难的。但是实际开发中经常需要回到上一个节点的情况。
  • 假设一个文本编辑器用链表来存储文本,当光标向上移动链表直接操作到下一个节点,但是光标向上移动呢,
    回不到上一个节点,就需要从head重新遍历,依次走到想要的节点上。

2.双向链表的简介和优点

  • 既可以从头遍历到尾,又可以从尾遍历到头。
  • 链表相连的过程是双向的。
  • 双向链表可以邮箱解决文本编译器的问题。
  • 每次在插入和删除的时候,需要处理四个引用,实现起来比较复杂。
  • 相较于单向链表,占用内存更大一些。

3.双向链表图解

  • 可以使用一个head和一个tail分别指向头部和尾部的节点
  • 每个节点由三部分组成:前一个节点的指针(prev)保存的元素(item)和后一个系欸但的指针(next)
  • 双向链表的第一个节点的prev是null
  • 双向链表最后的节点的next是null
    在这里插入图片描述

4.双向链表的封装

//双向链表的封装
    function DoubleLinkedList(){
        //属性
        this.head = null;
        this.tail = null;
        this.length = 0;

        function Node(data){
            this.data = data;
            this.prev = null;
            this.next = null;
        }
    }

    var doubleList = new DoubleLinkedList();

5.双向链表中常见操作。

  • append(element):向列表尾部添加一个元素
  • insert(position, element): 向特定位置插入一个元素
  • get(position): 获取对应位置的元素
  • indexOf(element): 返回元素在列表中的索引。没有返回-1
  • updata(position, element):修改某个位置的元素
  • removeAt(position):从列表的特定位置移除一项
  • remove(element): 从列表中移除一项
  • size() : 返回链表包含的元素个数
  • isEmpty(): 判断链表是否为空
  • toString():返回字符串
  • forwardString():返回正向遍历的节点字符串形式
  • backwardString(): 返回反向遍历的系欸但字符串形式

6.封装上述方法

6.1 append()方法的实现

 //append方法
    DoubleLinkedList.prototype.append = function (data) {
        let newNode = new Node(data);
        //判断是否插入的是第一个节点
        if (this.length == 0) {
            //让头尾指针都指向这个节点
            this.head = newNode;
            this.tail = newNode;
        } else {
            //不是第一个节点的话
            //让尾节点的next指向新的节点
            this.tail.next = newNode;
            //新节点的前指针指向尾节点
            newNode.prev = this.tail;
            //新节点替换之前的尾节点成为新的尾节点
            this.tail = newNode;
        }
        this.length += 1;
    }

6.2三个string方法的实现

 //toString()方法
    DoubleLinkedList.prototype.toString = function () {
        //从前往后遍历
        return this.backwardString();
    }


    //forwardString()方法
    DoubleLinkedList.prototype.forwardString = function () {
        var current = this.tail;
        var resultString = '';
        while (current) {
            resultString += current.data + ',';
            current = current.prev;
        }
        return resultString;
    }


    //backwardString()方法
    DoubleLinkedList.prototype.backwardString = function () {
        //1.定义变量
        var current = this.head;
        var resultString = '';
        while (current) {
            resultString += current.data + ' ';
            current = current.next;
        }

        return resultString;
    }

6.3 insert方法

DoubleLinkedList.prototype.insert = function (position, element) {
    //1.越界判断
    if (position < 0 || position > this.length) {
        return false;
    }
    //2.根据data创建新的节点
    var newNode = new Node(element);

    //3.判断原来的列表是否为空
    if (this.length == 0) {
        this.head = newNode;
        this.tail = newNode;
    } else {
        if (position == 0) {
            //让原来的节点的prev指向新的节点
            this.head.prev = newNode;
            //让新的节点的next指向原来的节点
            newNode.next = this.head;
            //修改head指向新节点
            this.head = newNode;
        } else if (position == this.length) {
            newNode.prev = this.tail;
            this.tail.next = newNode;
            this.tail = newNode;
        } else {
            var current = this.head;
            var index = 0;
            while (index++ < position) {
                current = current.next;
            }
            //修改指针
            newNode.next = current;
            newNode.prev = current.prev;
            current.prev.next = newNode;
            current.prev = newNode;
        }
        this.length += 1;
        return true;
    }

}

6.4get方法

 //get方法
    DoubleLinkedList.prototype.get = function (position) {
        //1.越界判断
        if (position < 0 || position >= this.length) {
            return null;
        }
        //如果this.length / 2 > position  从前往后遍历
        //如果this.length / 2 < position  从后往前遍历
        var previous = this.tail;
        var current = this.head;
        if (position < this.length / 2) {
            var index = 0;
            while (index++ < position) {
                current = current.next;
            }
            return current.data
        } else {
            var index = this.length - 1;
            while (index-- > position) {
                previous = previous.prev;
            }
            return previous.data;
        }
    }

6.5updata方法

//updata()方法
    DoubleLinkedList.prototype.updata = function (position, newData) {
        //边界判断
        if (position < 0 || position > this.length) {
            return false;
        }
        //寻找
        if (position < this.length / 2) {
            var index = 0;
            var current = this.head;
            while (index++ < position) {
                current = current.next;
            }
            current.data = newData;
        } else {
            var index = this.length - 1;
            var previous = this.tail;
            while (position < index--) {
                previous = previous.prev;
            }
            previous.data = newData;
        }

    }

6.6indexOf方法

//indexOf()方法
    DoubleLinkedList.prototype.indexOf = function (element) {
        var index = 0;
        var current = this.head;
        while (current) {
            if (current.data == element) {
                return index;
            }
            current = current.next;
            index++;
        }
        return -1;
    }

6.7removeAt方法

//removeAt方法
DoubleLinkedList.prototype.removeAt = function (position) {
    //1.边界判断
    if (position < 0 || position > this.length) {
        return false;
    }
    //2.加入只有一个节点(长度唯一)
    if (this.length == 1) {
        this.head = null;
        this.tail = null;
        //长度不为1的时候判断删除的是否是第一个节点
    } else {
        if (position == 0) {
            this.head.next.prev = null;
            this.head = this.head.next;
        }
        else if(position == this.length - 1){
            this.tail.prev.next = null;
            this.tail = this.tail.prev;
        } else{
            var index = 0;
            if(position < this.length /2){
                var current = this.head;
                while(index++ < position){
                    current = current.next;
                }
                current.prev.next = current.next;
                current.next.prev = current.prev;
            } else{
                var previous = this.tail;
                var index = this.length -1;
                while(position < index--){
                    previous = previous.prev;
                }
                previous.prev.next = previous.next;
                previous.next.prev = previous.prev;
            }
        }
    }
    this.length -= 1;
    return true;

}

6.8remove方法

 //8.remove方法
    LinkedList.prototype.remove = function (data) {
        //1.获取data在列表中的位置
        let position = this.indexOf(data);

        //2.根据位置信息,删除节点

        //3.length - 1
        this.length -= 1;
        return this.removeAt(position);
    }

6.9其他的小方法

//isEmpty()方法
    DoubleLinkedList.prototype.isEmpty = function () {
        return this.length == 0;
    }

    //size()方法
    DoubleLinkedList.prototype.size = function () {
        return this.length;
    }
发布了85 篇原创文章 · 获赞 16 · 访问量 6093

猜你喜欢

转载自blog.csdn.net/qq_43955202/article/details/104545404