数据结构——链表(JavaScript)

我们可以想象成。。。。
这里写图片描述

链表存储有序的元素集合,在内存中元素是不连续的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。
这里写图片描述

单向链表

首先,我们需要创建一个数据结构用来作为链表的节点,节点包含value(用来存放数值)与next(用来存放下一个数据节点的地址)。
然后我们再实现一些方法。

方法
append(value):向列表尾插一个新的节点
insert(position, value):向列表的特定位置插入一个新的节点
remove(value):移除列表中元素值为value的项
indexOf(value):返回元素在列表中的索引值,如果没有该值,就返回-1
removeAt(position):从特定位置移除一项
isEmpty():判断链表是否为空
size():返回链表元素的个数
toString():输出元素的值
clear():清空链表

这里写图片描述

这里写图片描述

function linkedList(){

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

    var length = 0;
    var head = null;

    this.append = function(value){
        var node = new Node(value),
            temporary;
        if(head){//有元素循环至尾部添加
            temporary = head;
            while(temporary.next){
                temporary = temporary.next;
            }
            temporary.next = node;
        }else{//没有元素直接添加
            head = node;
        }
        length++;//长度+1
        return;
    }
    this.insert = function(position,value){
        //检查position是否越界
        if(position < 0 || position > length){
            console.log("position is error");
            return;
        }else{
            var node = new Node(value),
                temporary = head,
                front;
            if(!position){//为0时
                head = node;
                head.next = temporary; 
            }else{
                while(position--){//循环到目标节点的前一个节点
                    front = temporary;
                    temporary = temporary.next;
                }
                front.next = node;
                node.next = temporary;
            }
            length++;
            return;
        }
    }
    this.removeAt = function(position){
        //检查position是否越界
        if(position < 0 || position > length){
            console.log("position is error");
            return;
        }else{
            var temporary = head,
                front;
            if(!position){
                head = head.next;
            }else{
                while(position--){//一直循环到待删结点的前一个节点
                    front = temporary;//当前节点给前一个节点
                    temporary = temporary.next;//当前节点后移
                }
                front.next = temporary.next;
            }
            length--;//记住长度要-1
            return temporary.value;
        }
    }
    this.remove = function(value){
        var position = this.indexOf(value);
        return this.removeAt(position);
    }
    this.indexOf = function(value){
        var position = -1,
            temporary = head;
        while(temporary){
            if(temporary.value == value){
                return position;
            }
            temporary = temporary.next;
            position++;
        }
        return -1;
    }
    this.isEmpty = function(){
        return !length;
    }
    this.size = function(){
        return length;
    }
    this.toString = function(){
        var str = '',
            temporary = head;
        while(temporary){
            str += temporary.value + ' ';
            temporary = temporary.next;
        }
        return str;
    }
    this.print = function(){
        console.log(this.toString());
    }
    this.getHead = function(){
        return head;
    }
    this.clear = function(){
        head = null;
        length = 0;
    }
}

/*使用链表*/
var list = new linkedList();
list.append(5);
list.append(4);
list.insert(0,3);
list.append(2);
list.append(1);
list.print();
list.remove(0);
list.print();
list.removeAt(0);
list.print();
console.log(list.size());
list.clear();
console.log(list.isEmpty());

控制台输出:
这里写图片描述

双向链表

双向链表与单向链表的区别在于其节点存储紧前节点,紧后节点,数值。

如图:
这里写图片描述

双向链表删除(三种情况)

头删

这里写图片描述

尾删

这里写图片描述

中间删

这里写图片描述

双向链表插入(三种情况)

头插

这里写图片描述

尾插

这里写图片描述

中间插

这里写图片描述

function DoulyLinkedList(){
    //定义节点并初始化
    var Node = function(value){
        this.value = value;
        this.prev = null;
        this.next = null;
    }
    var head = null,
        tail = null,
        length = 0;

    //定义方法
    this.append = function(value){
        var node = new Node(value),
            temporary;
        if(head){//有元素循环至尾部添加
            tail.next = node;
            node.prev = tail;
            tail = node;
        }else{//没有元素直接添加
            head = node;
            tail = node;
        }
        length++;//长度+1
        return;
    }
    this.insert = function(position,value){//在任意节点插入元素
        //判断position是否正确
        if(position < 0 || position > length){
            return false;
        }else{
            var node = new Node(value),
                front,
                temporary = head;
            if(!position){//头插
                if(!head){
                    head = node;
                    tail = node;
                }else{
                    node.next = temporary;
                    temporary.prev = node;
                    head = node;
                }
            }else if(position-length){//中间插
                while(position--){
                    front = temporary;
                    temporary = temporary.next;
                }
                front.next = node;
                node.prev = front;
                node.next = temporary;
                temporary.prev = node;
            }else{//尾插
                tail.next = node;
                node.prev = tail;
                tail = node;
            }
            length++;
            return true;
        }
    }
    this.removeAt = function(position){
        //检查是否越界
        if(position < 0 || position > length){
            console.log("postion is crossing!");
            return false;
        }else{
            var front,
                temporary = head;
            if(!position){//删除第一个
                head = head.next;
                //注意,这里需要判断链表中元素是否只有一个
                if(length === 1){
                    tail = null;
                }else{
                    head.prev = null;
                }
            }else if(position-length){//删除中间元素
                while(position--){//找出待删结点temporary以及紧前节点front
                    front = temporary;
                    temporary = temporary.next;
                }
                //连接两个节点
                front.next = temporary.next;
                temporary.next.prev = front;
            }else{//删除最后一个
                tail = tail.prev;
                tail.next = null;
            }
            length--;//长度-1
            return temporary.value;
        }
    }
    this.remove = function(value){
        var position = this.indexOf(value);
        return this.removeAt(position);
    }
    this.indexOf = function(value){
        var position = -1,
            temporary = head;
        while(temporary){
            if(temporary.value == value){
                return position;
            }
            temporary = temporary.next;
            position++;
        }
        return -1;
    }
    this.isEmpty = function(){
        return !length;
    }
    this.size = function(){
        return length;
    }
    this.toString = function(){
        var str = '',
            temporary = head;
        while(temporary){
            str += temporary.value + ' ';
            temporary = temporary.next;
        }
        return str;
    }
    this.print = function(){
        console.log(this.toString());
    }
    this.getHead = function(){
        return head;
    }
    this.clear = function(){
        head = null;
        length = 0;
    }
}

//使用双向链表,此处代码与单向链表使用过程相同,所以结果显示一项
var list = new DoulyLinkedList();
list.append(5);
list.append(4);
list.insert(0,3);
list.append(2);
list.append(1);
list.print();
list.remove(0);
list.print();
list.removeAt(0);
list.print();
console.log(list.size());
list.clear();
console.log(list.isEmpty());

这里写图片描述

循环链表

最后一个元素指向下一个元素的指针(tail.next)不是引用null, 而是指向第一个元素(head),第一个元素指向前一个元素的指针不是引用null,而是最后一个元素。

这里写图片描述

循环链表与双向链表的创建代码非常相似,自行发挥。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值