(四)学习JavaScript数据结构与算法——链表

链表是一种动态的数据结构,下面说说数组和链表间的对比:

  • 数组由于可以通过下标查找对应的元素,所以查询方便,但是对于插入和删除操作,需要遍历,所以消耗比较大
  • 链表的特点与数组相反,它由于不是顺序存储,所以插入和删除都比较方便,但是查询某个元素就比较麻烦,需要从头开始遍历

1)链表的特点:

  • 存储位置不连续
  • 每个元素由存储本身的节点和一个指向下一个元素的引用组成

2)链表的实例:

  • 寻宝游戏

3)基本骨架:

function LinkedList(){
        let Node=function(element){ //链表的元素
            this.element=element;//元素的内容
            this.next=null;//指向下一个的指针
        };
        let length=0;
        let head=null;//头指针
        this.append=function(element){};//向尾部添加一个新的项
        this.insert=function(position,element){};//向链表特定位置插入一个新的项
        this.removeAt=function(position){};//移除特定位置的项
        this.remove=function(element){};//移除一项
        this.indexOf=function(element){};//返回元素在列表中的索引,没有返回-1
        this.isEmpty=function(){};//链表中不含任何元素,则返回true,否则,返回false
        this.size=function(){};//返回包含的元素个数
        this.getHead=function(){};//返回头指针
        this.toString=function(){};//输出链表中的内容
        this.print=function(){};
    }

4)具体实现

增:

a.向链表尾部追加元素

 this.append=function(element){
            let node=new Node(element),//现将元素转为节点的形式
                    current;//用于存放当前头指针
            if(head===null){
                head=node;//如果为空,则直接将该元素赋值给头指针
            }else{
                current=head;//如果不为空,将头指针保存在current变量
                while(current.next){
                    current=current.next;//循环列表,直到最后一项
                }
                current.next=node;//找到最后一项,将其next赋值为node,建立连接
            }
            length++;//更新链表的长度
        };//向尾部添加一个新的项

b.在任意位置插入元素

this.insert=function(position,element){
            if(position>=0&&position<=length){
                let node=new Node(element),
                        current=head,
                        previous,
                        index;
                if(position===0){
                    node.next=current;
                    head=node;
                }else{
                    while(index++<position){
                        previous=current;
                        current=current.next;
                    }
                    node.next=current;
                    previous.next=node;
                }
                length++;//更新列表长度
                return true;
            }else{
                return false;
            }
        };//向链表特定位置插入一个新的项

删:

a.从链表中移除元素

this.removeAt=function(position){
            //检查越界值
            if(position>-1&&position<length){
                let current=head,//指向第一个元素
                        previous,
                        index=0;
                //移除第一项
                if(position===0){
                    head=current.next;//将第二个元素赋值给头指针
                }else{
                    while(index++<position){
                        previous=current;
                        current=current.next;
                    }
                    previous.next=current.next;//将previous与current的下一项连接起来,跳过current,从而实现移除
                }
                length--;
                return current.element;
            }else{
                return null;//如果越界,则返回null;
            }
        };//移除特定位置的项

b.remove方法

 this.remove=function(element){
            let index=this.indexOf(element);
            return this.removeAt(index);
        };//移除一项

其他:

toString方法

this.toString=function(){
            let current=head,
                    string='';
            while(current){
                string+=current.element+(current.next?'n':'');
                current=current.next;
            }
            return string;
        };//输出链表中的内容

indexOf方法:

 this.indexOf=function(element){
            let current=head,
                    index=-1;
            while(current){
                if(element===current.element){
                    return index;
                }
                index++;
                current=current.next;
            }
            return -1;
        };//返回元素在列表中的索引,没有返回-1

isEmpty方法:

 this.isEmpty=function(){
            return length==0;
        };//链表中不含任何元素,则返回true,否则,返回false

size方法:

 this.size=function(){
            return length;
        };//返回包含的元素个数

getHead方法:

this.getHead=function(){
            return head;
        };//返回头指针

完整功能实现代码:

    function LinkedList(){
        let Node=function(element){ //链表的元素
            this.element=element;//元素的内容
            this.next=null;//指向下一个的指针
        };
        let length=0;
        let head=null;//头指针
        this.append=function(element){
            let node=new Node(element),//现将元素转为节点的形式
                    current;//用于存放当前头指针
            if(head===null){
                head=node;//如果为空,则直接将该元素赋值给头指针
            }else{
                current=head;//如果不为空,将头指针保存在current变量
                while(current.next){
                    current=current.next;//循环列表,直到最后一项
                }
                current.next=node;//找到最后一项,将其next赋值为node,建立连接
            }
            length++;//更新链表的长度
        };//向尾部添加一个新的项
        this.insert=function(position,element){
            if(position>=0&&position<=length){
                let node=new Node(element),
                        current=head,
                        previous,
                        index;
                if(position===0){
                    node.next=current;
                    head=node;
                }else{
                    while(index++<position){
                        previous=current;
                        current=current.next;
                    }
                    node.next=current;
                    previous.next=node;
                }
                length++;//更新列表长度
                return true;
            }else{
                return false;
            }
        };//向链表特定位置插入一个新的项
        this.removeAt=function(position){
            //检查越界值
            if(position>-1&&position<length){
                let current=head,//指向第一个元素
                        previous,
                        index=0;
                //移除第一项
                if(position===0){
                    head=current.next;//将第二个元素赋值给头指针
                }else{
                    while(index++<position){
                        previous=current;
                        current=current.next;
                    }
                    previous.next=current.next;//将previous与current的下一项连接起来,跳过current,从而实现移除
                }
                length--;
                return current.element;
            }else{
                return null;//如果越界,则返回null;
            }
        };//移除特定位置的项
        this.remove=function(element){
            let index=this.indexOf(element);
            return this.removeAt(index);
        };//移除一项
        this.indexOf=function(element){
            let current=head,
                    index=-1;
            while(current){
                if(element===current.element){
                    return index;
                }
                index++;
                current=current.next;
            }
            return -1;
        };//返回元素在列表中的索引,没有返回-1
        this.isEmpty=function(){
            return length==0;
        };//链表中不含任何元素,则返回true,否则,返回false
        this.size=function(){
            return length;
        };//返回包含的元素个数
        this.getHead=function(){
            return head;
        };//返回头指针
        this.toString=function(){
            let current=head,
                    string='';
            while(current){
                string+=current.element+(current.next?'n':'');
                current=current.next;
            }
            return string;
        };//输出链表中的内容
    }

链表进阶:

  • 双向链表
    • 特点:在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素,这样就提供了两种迭代列表的方法:从头到尾或者从尾到头。
    • 实现的方法:

1)基本骨架:

function DoublyLinkedList(){
        let Node=function(element){
            this.element=element;
            this.next=null;//头指针
            this.prev=null;//尾指针
        }
        let length=0;
        let head=null;
        let tail=null;
}

2)任意位置插入元素

this.insert=function(position,element){
            //检查越界值
            if(position>=0&&position<=length){
                let node=new Node(element),
                        current=head,
                        previous,
                        index=0;
                if(position===0){ //在第一个位置插入元素
                    if(!head){ //没有元素时,头尾指针均指向node
                        head=node;
                        tail=node;
                    }else{
                        node.next=current;
                        current.prev=node;
                        node.prev=current;
                        tail=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;
            }
        }

3)从任意位置移除元素

        this.removeAt=function(position){
            if(position>-1&&position<length){
                let current=head,
                        previous,
                        index=0;
                //移除第一项
                if(position===0){
                    head=current.next;
                    if(length===1){
                        tail=null;//如果只有一项,更新tail
                    }else{
                        head.prev=null;//将新加入的第一项元素的prev指针设置为空
                    }
                }else if(position===length-1){
                    current=tail;
                    tail=current.prev;
                    tail.next=null;
                }else{
                    while(index++<position){
                        previous=current;
                        current=current.next;
                    }
                    previous.next=current.next;
                    current.next.prev=previous;
                }
                length--;
                return current.element;
            }else{
                return null;//越界处理
            }
        }
  • 循环列表
    • 特点:最后一个元素的指向下一个元素的指针指向第一个元素

猜你喜欢

转载自blog.csdn.net/tozeroblog/article/details/82753638
今日推荐