数据结构与算法4:用JavaScript 实现 双向链表 结构

本文详细介绍了双向链表的概念及其特点,包括其数据结构和常用操作如追加、插入、获取、查找、更新和删除元素。还提供了一个JavaScript实现的双向链表类,包含了各种操作方法,并通过示例展示了其用法。

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

特点

  1. 可以用一个head 和一个tail 分别指向头和尾的节点
  2. 每个节点都由三部分组成:前一个节点的指针(prev)/保存元素(item)/后一个节点的指针(next)
  3. 双向链表的第一个节点的prev是null
  4. 双向链表的最后节点的next是null

常用方法

  • append(data) 追加元素
  • insert(position, data) 插入节点
  • get(position) 查看元素
  • indexOf(element) 返回元素在列表中的索引
  • updata(position) 修改某个位置的元素
  • remove(position/data) 从列表的特定位置(数据)移除一项
  • isEmpty() 如果链表中不包含任何元素,返回true,否则为false
  • size() 返回链表包含的元素个数,与数组的length类似
// 封装双向链表
function DoublyLinkedList() {
    // 封装内部类
    function Node (data){
        this.data = data;
        this.prev = null;
        this.next = null;
    }

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

    // 常见方法
     // 1 append追加
     DoublyLinkedList.prototype.append = function (data) {
        var newNode = new Node(data);
        // 判断是否空链表
        if (this.length === 0 ) {
            this.head = newNode;
            this.tail =newNode;
        }else{
            newNode.prev = this.tail;
            // 更新尾指针
            this.tail.next = newNode;
            this.tail = newNode;
        }
        // 更新链表长度
        this.length += 1 
    }

    // 2 toString转字符串
    DoublyLinkedList.prototype.toString = function () {
        return this.backwardString()
    }

    // 2.2 forwardString方法
    DoublyLinkedList.prototype.forwardString = function () {
        var current = this.tail;
        var result = '';
        // 依次向前遍历各个节点
        while (current) {
            result += current.data + " " ;
            current = current.prev;
        }
        return result
    }

    // 2.2 backwardString方法
    DoublyLinkedList.prototype.backwardString = function () {
        var current = this.head;
        var result = '';
        // 依次向前遍历各个节点
        while (current) {
            result += current.data + " " ;
            current = current.next;
        }
        return result
    }

    // 3 insert插入节点
    DoublyLinkedList.prototype.insert = function (position, data) {
        // 1 对position进行越界判断
        if (position < 0 || position >= this.length) return false

        // 2 根据data创建节点
        var newNode = new Node(data)
        
        // 3 判断链表是否为空
        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) {
                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;
    }

    // 4 get方法
    DoublyLinkedList.prototype.get = function (position) {
        // 1 对position进行越界判断
        if (position < 0 || position >= this.length) return false
        // 获取元素
        var index = 0;
        var current = this.head;  
        while (index++ < position) {
            current = current.next
        }
        return current.data
    }

    // 5 indexOf(element)返回元素在列表中的索引
    DoublyLinkedList.prototype.indexOf = function (element) {
        var current = this.head;
        var index = 0;
        while (current) {
            if (current.data === element) {
                return index
            }
            current = current.next;
            index += 1;
        }
        return false
    }

    // 6 updata(position)修改某个位置的元素
    DoublyLinkedList.prototype.updata = function (position, newdata) {
        // 由于又position信息,故需要进行越界判断
        if (position < 0 || position >= this.length) return false

        var current = this.head;
        var index = 0;
        while (index++ < position) {
            current = current.next;
        }
        current.data = newdata;
    }

    // 7 removeAt(position)从列表的特定位置移除一项
    DoublyLinkedList.prototype.removeAt = function (position) {
        if (position < 0 || position >= this.length) return null

        var current = this.head;
        // 判断是否只有一个节点
        if (this.length === 1) {
            this.head = null;
            this.tail = null;
        }else {
            // 当头指针需要剔除时
            if (position === 0 ) {
                this.head = this.head.next;
                this.head.prev = null;
            }
            // 当尾节点需要剔除时
            else if (position === this.length - 1) {
                current = this.tail;
                this.tail = this.tail.prev;
                this.tail.next = null
            }
            // 其它情况
            else {
                var index = 0;
                while (index++ < position) {
                    current = current.next;
                }
                current.next.prev = current.prev;
                current.prev.next = current.next;
            } 
        }
        this.length -= 1;
        return current.data 
    }

    // 8 remove(element)从列表中移除一项
    DoublyLinkedList.prototype.remove = function (element) {
        // 查找位置
        var position = this.indexOf(element);
        // 删除
        return this.removeAt(position);
    }

    // 9 isEmpty() 如果链表中不包含任何元素,返回true,否则为false
    DoublyLinkedList.prototype.isEmpty = function () {
        return this.length === 0 
    }

    // 10 size() 返回链表包含的元素个数,与数组的length类似
    DoublyLinkedList.prototype.size = function () {
        return this.length
    }
}

// 测试代码
var list = new DoublyLinkedList();
list.append('111');
list.append('222');
list.append('333');
console.log(list.toString());
list.remove('111');
console.log(list.toString());
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值