使用JS实现双向链表

68 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

1.双向链表

双向链表和普通链表的区别在于,在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的,一个链向下一个元素,另一个链向前一个元素

2.双向链表的优缺点

每次在插入或删除某个节点时,都需要处理四个引用,而不是两个,实现起来会困难些
相对于单向链表,所占内存空间更大一些;
但是,相对于双向链表的便利性而言,这些缺点微不足道。

3.双向链表的常见操作:

append(element):向链表尾部添加一个新的项;
inset(position,element):向链表的特定位置插入一个新的项;
get(element):获取对应位置的元素;
indexOf(element):返回元素在链表中的索引,如果链表中没有元素就返回-1;
update(position,element):修改某个位置的元素;
removeAt(position):从链表的特定位置移除一项;
isEmpty():如果链表中不包含任何元素,返回trun,如果链表长度大于0则返回false;
size():返回链表包含的元素个数,与数组的length属性类似;
toString():由于链表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值;
forwardString():返回正向遍历节点字符串形式;
backwordString():返回反向遍历的节点的字符串形式;
getHead():返回链表首个元素
getTail():返回链表最后一个元素

在这里插入图片描述

   function DoubleLinklist(){
            // 封装内部类,节点类

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

            // 属性
            this.head = null;
            this.tail = null;
            this.length = 0;

            //方法
            DoubleLinklist.prototype.append = function (element){

                let newNode = new Node(element);
                if(this.length == 0){
                    this.head = newNode;
                    this.tail = newNode;
                }else{
                    // 添加的不是一个节点
                    this.tail.next = newNode;
                    newNode.prev = this.tail; 
                    this.tail = newNode;
                }

                this.length++;
            }

            DoubleLinklist.prototype.forwardString = function (){   

                let current = this.tail;
                let objString = '';
                // 向前遍历
                while(current){
                   objString += current.data + ' ';
                   current  =  current.prev;
                }
                return objString;
            }

            DoubleLinklist.prototype.backwardString = function(){

                let current = this.head;
                let objString = '';
                while(current){
                    objString += current.data + ' ';
                    current = current.next;
                }
            return objString;
            }

            DoubleLinklist.prototype.toString = function(){

                   return  this.backwardString();
            }

            // 插入操作

            DoubleLinklist.prototype.insert = function (position,element){

                // 边界值判断
                if(position < 0 || position > this.length-1 ) return false;

                let newNode = new Node(element);

                // 原链表为空插入的newNode是第一个节点
                if(this.length == 0){
                    this.head = newNode;
                    this.tail = newNode;
                }else{
                // 原链表不为空
                    if(position == 0){
                    this.head.prev = newNode;
                    newNode.next = this.head;
                    this.head = newNode;
                }
                else if(position == this.length){
                    this.append(element);
                }
                else{
                    let current = this.head;
                    let previous = null;
                    let index = 0;
                    while(index++ < position){
                        previous = current;
                        current = current.next;
                    }
                    previous.next = newNode;
                    newNode.prev = previous;
                    newNode.next = current;
                    current.prev = newNode;
                }
                }
                
                this.length += 1;
            }

            DoubleLinklist.prototype.get = function(position){
                //边界值分析
                if(position < 0 || position > this.length-1) return false;

                // 2.获取元素
                if((this.length / 2) > position){
                    // 此时从头开始遍历
                    let current = this.head;
                    let index = 0;
                    while(index++ < position){
                        current = current.next;
                    } 
                   return  current.data;
                }else{
                    // 从后遍历更快
                    let current = this.tail;
                    let index = this.length-1;
                    while(index-- > position){
                        current = current.prev;
                    }
                return current.data;
                } 
            }

            DoubleLinklist.prototype.indexOf = function(element){

                if(this.length == 0) return -1;

                let current = this.head;
                let index = 0;
                while(current){
                    if(current.data == element){
                        return index;
                    }
                    index++;
                    current = current.next;
                }
                return -1;
            }

            // 更新
            DoubleLinklist.prototype.update = function(position,element){

                // 边界值分析
                if(position < 0 || position > this.length-1) return false;

                let current = null;
                 let index = 0;
                // 从头部开始遍历
                if(position < this.length / 2){
                    current = this.head;
                    index = 0;
                    while(index++ < position){
                        current = current.next;
                    }
                }else{
                    //从尾部开始遍历
                    current = this.tail;
                   index = this.length - 1;
                    while(index-- > position){
                        current = current.prev;
                    }

                }
                current.data = element;
                return current.data;  //返回修改成功的数据或者true

            }

            // 移除元素
            DoubleLinklist.prototype.removeAt = function(position){
                // 边界值分析
                if(position < 0 || position > this.length-1) return false;

                let current = this.head;

                if(this.length == 1){
                    this.head = null;
                    this.tail = null;
                }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{    //中间的元素
                        let index = 0;
                        while(index++ < position){
                            current = current.next;
                        }
                        current.prev.next = current.next;
                        current.next.prev = current.prev;
                    }
                }

                this.length -= 1;
                return current.data; //返回被删除节点的数据

            }

            DoubleLinklist.prototype.remove = function(element){

                // 1.根据element获取下标
                let index = this.indexOf(element);

                // 2.根据index删除对应位置的节点
                return this.removeAt(index);
            }

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

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

            // 获取链表第一个元素
            DoubleLinklist.prototype.getHead = function(){
                return this.head.data;
            }
            DoubleLinklist.prototype.getTail = function(){
                return this.tail.data;
            }




        }

测试代码:

     let douList = new DoubleLinklist();
        douList.append('aaaa');
        douList.append('bbbb');
        douList.append('cccc');

        douList.insert(0,'FBI');
        douList.insert(2,'BBC');
        douList.insert(5,'GGG');

        console.log(douList);
        console.log(douList.forwardString());
        console.log(douList.backwardString());
        console.log(douList.get(2));
        console.log(douList.get(4));

        console.log(douList.indexOf('cccc'));
        console.log(douList.update(1,'Amy'));
        console.log(douList.update(0,'jack'));
        console.log(douList.update(4,'theshy'));
        console.log(douList.backwardString());
        console.log(douList.removeAt(0));
        console.log(douList.removeAt(1));
        console.log(douList.backwardString());
        console.log(douList.remove('Amy'));
        console.log(douList.backwardString());
        console.log(douList.size());
        console.log(douList.getHead());
        console.log(douList.getTail());