数据结构(JS实现)——双向链表的实现

2,238 阅读3分钟

@[toc]

一、什么是双链表?

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

在这里插入图片描述

二、双向链表的特点

  • 可以使用head和一个tail分别指向头部和尾部的节点
  • 每个节点都由三部分组成:前一个节点的指针,后一个节点的指针,元素
  • 双向链表的第一个节点prev是null
  • 双向链表的最后的节点next是null;

三、 双向链表的封装

function DoublyLinkedList() {
        // Node节点
        function Node(data) {
            this.prev=null;
            this.item=data;
            this.next=null;
        }
        // 属性
        this.head=null;//头节点
        this.tail=null;//尾节点
        this.length=0;//长度
    }

四、双链表常见的操作(增删改查)

  1. append(element):向链表尾部添加一个新的项
  2. insert(position,element):向链表的特定位置插入一个新的项
  3. get(position):获取对应位置的元素
  4. indexOf(element):返回元素在列表上的索引。如果链表上没有该元素则返回-1
  5. updata(position,element):更新某个元素
  6. removeAt(position):从链表的特定位置移除一项(根据位置)
  7. remove(element);从链表移除一项(根据元素)
  8. isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。
  9. size():返回链表包含的元素个数。
  10. tostring():输出
  11. forwardString():返回正向遍历的节点字符串形式
  12. backworkString():返回正向遍历的节点字符串形式

4.1 append(element):向链表尾部添加一个新的项

步骤:

1.创建新的节点(newNode)

2.判断是否添加的是第一个节点

3.若是:如图1

4.不是:如图2

5.length++

图1:

在这里插入图片描述

图2:

在这里插入图片描述

DoublyLinkedList.prototype.append=function(data){
            // 1.根据data创建节点
            var newNode=new Node(data);
            // 2.判断添加的是否为第一个节点
            if (this.length==0) {
                this.head=newNode;
                newNode.prev=null;
                this.tail=newNode;
            } else {
                this.tail.next=newNode;
                newNode.prev=this.tail;
                this.tail=newNode;
            }
            // 3.length++
            this.length+=1;
        }

4.2 insert(position,element):向链表的特定位置插入一个新的项

步骤:

1.越界判断

2.创建新的节点

3.判断此时链表是否为空

3.1 空:与head。tail连接

3.2 不为空

3.3.1 position=0

3.3.2 position=length

3.3.3 postion在中间

在这里插入图片描述

DoublyLinkedList.prototype.insert = function (position, data) {
            // 1.越界判断
            if (position < 0 || position > this.length) {
                return false;
            }
            // 2.创建新的节点
            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;
                    var previous=null;
                    while (index<position) {
                        previous=current;
                        current=current.next;
                        index+=1;
                    }
                    //**
                    newNode.prev=previous;
                    previous.next=newNode;
                    newNode.next=current;
                    current.prev=newNode;
                }
            }
            length+=1;
            return true;
        }

4.3 get(position):获取对应位置的元素

步骤:

1.position越界判断

2.遍历get元素data


  DoublyLinkedList.prototype.get = function (position) {
            // 1.position越界判断
            if (position < 0 || position >= this.length) {
                return null;
            }
            // 2.遍历get元素data
            var current = this.head;
            var index=0;
            while (index<position) {
                current = current.next;
                index+=1;
            }
            return current.data;
        }

4.4 indexOf(element):返回元素在列表上的索引。如果链表上没有该元素则返回-1

步骤:

遍历求值

  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 -1;
        }

4.5 updata(position,element):更新某个元素

步骤:

1.position边界值

2.遍历找到position值并替换

  DoublyLinkedList.prototype.updata = function (position,element) {
            //1.position边界值
            if (position<0||position>=this.length) {
                return false;
            }
            //2.遍历找到position值并替换
            var current=this.head;
            var index=0;
            while (index++<position) {
                current=current.next;
            }
            current.data=element;
            return true;
        }

4.6 removeAt(position):从链表的特定位置移除一项(根据位置)

步骤:

判断越界

1、判断链表长度是否为1

2、若无为1则处理

3、不为1则:position=0

3.1、position=0

3.2、position=middle

3.3、position=this.length-1

4.length--

在这里插入图片描述

 DoublyLinkedList.prototype.removeAt = function (position) {
            // 越界
            if (position < 0 || position >= this.length) {
                return false;
            }
            //1、判断链表长度是否为1
            if (this.length == 1) {
                this.head = null;
                this.tail = null;
            } else {
                //3、不为1则
                //3.1、position=0
                if (position == 0) {
                    this.head = this.head.next;
                    this.head.prev = null;
                    //3.3、position=this.length-1
                } else if (position == this.length - 1) {
                    console.log('执行');
                    this.tail = this.tail.prev;
                    this.tail.next = null;
                    //3.2、position=middle
                } else {
                    var current = this.head;
                    var index = 0;
                    while (index++ < position) {
                        current = current.next;
                    }
                    current.prev.next = current.next;
                    current.next.prev = current.prev;
                }
            }
            //4.length--
            this.length -= 1;
            return true;
        }

4.7 remove(element);从链表移除一项 (根据元素)

步骤

this.removeAt(this.indexOf(element))

  DoublyLinkedList.prototype.remove=function(element){
           return this.removeAt(this.indexOf(element));
        }

3.8 isEmpty():判空

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

3.9 size():返回链表包含的元素个数。

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

3.10 tostring():输出

1.定义变量;

2.依次向后遍历,获取节点

3.返回str

DoublyLinkedList.prototype.tostring=function(){
            // 1.定义变量;
            // 2.依次向后遍历,获取节点
            // 3.返回str
            var current=this.head;
            var str=''
            while (current) {
                str+=current.data+' '
                current=current.next;
            }

五.源码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    function DoublyLinkedList() {
        // Node节点
        function Node(data) {
            this.prev = null;
            this.data = data;
            this.next = null;
        }
        // 属性
        this.head = null;//头节点
        this.tail = null;//尾节点
        this.length = 0;//长度



        /* append(element):向链表尾部添加一个新的项 */
        DoublyLinkedList.prototype.append = function (data) {
            // 1.根据data创建节点
            var newNode = new Node(data);
            // 2.判断添加的是否为第一个节点
            if (this.length == 0) {
                this.head = newNode;
                newNode.prev = null;
                this.tail = newNode;
            } else {
                this.tail.next = newNode;
                newNode.prev = this.tail;
                this.tail = newNode;
            }
            // 3.length++
            this.length += 1;
        }

        /*  insert(position,element):向链表的特定位置插入一个新的项*/
        DoublyLinkedList.prototype.insert = function (position, data) {
            // 1.越界判断
            if (position < 0 || position > this.length) {
                return false;
            }
            // 2.创建新的节点
            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;
                        index += 1;
                    }
                    current.prev.next = newNode;
                    newNode.prev = current.prev;
                    newNode.next = current;
                    current.prev = newNode;
                }
            }
            this.length += 1;
            return true;
        }

        /*get(position):获取对应位置的元素 */
        DoublyLinkedList.prototype.get = function (position) {
            // 1.position越界判断
            if (position < 0 || position >= this.length) {
                return null;
            }
            // 2.遍历get元素data
            var current = this.head;
            var index = 0;
            while (index < position) {
                current = current.next;
                index += 1;
            }
            return current.data;
        }

        /*  indexOf(element):返回元素在列表上的索引。如果链表上没有该元素则返回-1 */
        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 -1;
        }

        /*updata(position,element):更新某个元素*/
        DoublyLinkedList.prototype.updata = function (position, element) {
            //1.position边界值
            if (position < 0 || position >= this.length) {
                return false;
            }
            //2.遍历找到position值并替换
            var current = this.head;
            var index = 0;
            while (index++ < position) {
                current = current.next;
            }
            current.data = element;
            return true;
        }

        /*  removeAt(position):从链表的特定位置移除一项(根据位置) */
        DoublyLinkedList.prototype.removeAt = function (position) {
            // 越界
            if (position < 0 || position >= this.length) {
                return false;
            }
            //1、判断链表长度是否为1
            if (this.length == 1) {
                this.head = null;
                this.tail = null;
            } else {
                //3、不为1则
                //3.1、position=0
                if (position == 0) {
                    this.head = this.head.next;
                    this.head.prev = null;
                    //3.3、position=this.length-1
                } else if (position == this.length - 1) {
                    console.log('执行');
                    this.tail = this.tail.prev;
                    this.tail.next = null;
                    //3.2、position=middle
                } else {
                    var current = this.head;
                    var index = 0;
                    while (index++ < position) {
                        current = current.next;
                    }
                    current.prev.next = current.next;
                    current.next.prev = current.prev;
                }
            }
            //4.length--
            this.length -= 1;
            return true;
        }


        /* remove(element);从链表移除一项(根据元素) */
        DoublyLinkedList.prototype.remove=function(element){
           return this.removeAt(this.indexOf(element));
        }

        /* isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。 */
        DoublyLinkedList.prototype.isEmpty=function(){
           return this.length==0
        }


         /* size():返回链表包含的元素个数。 */
         DoublyLinkedList.prototype.size=function(){
            return this.length;
        }



        /* tostring():输出 */
        DoublyLinkedList.prototype.tostring = function () {
            // 1.定义变量;
            // 2.依次向后遍历,获取节点
            // 3.返回str
            var current = this.head;
            var str = ''
            while (current) {
                str += current.data + ' '
                current = current.next;
            }
            return str;
        }
        /* forwardString():返回正向遍历的节点字符串形式 */
        DoublyLinkedList.prototype.forwardString = function () {
            var current = this.head;
            var str = ''
            while (current) {
                str += current.data + ' '
                current = current.next;
            }
            return str;
        }
        /* backworkString():返回正向遍历的节点字符串形式 */
        DoublyLinkedList.prototype.backworkString = function () {
            var current = this.tail;
            var str = ''
            while (current) {
                str += current.data + ' '
                current = current.prev;
            }
            return str;
        }
    }

    var list = new DoublyLinkedList();
    list.append('mmm');
    list.append('nnn');
    list.append('ccc');
    list.append('cba');
    list.append('nba');
    list.append('bbb');
    console.log(list.size());

</script>

</html>