双向链表

 什么是双向链表?

既可以从头遍历到尾,又可以从尾遍历到头,一个节点机油向前链接的引用,也有向后链接的引用

双向链表的缺点:

每次在插入或者删除某个节点的时候,需要处理四个引用,而不是两个,相对于单向链表,占用较多的内存空间,但是在使用层度上这些是微不足道的。

 

双向链表的操作

<1>  append(element):向列表尾部添加一个新的项

<2>  insert(position,element):向列表的特定位置插入一个新的项

<3>  get(position):获取对应位置的元素

<4>  indexOf(element):返回元素在列表中的索引,如果列表中没有该元素则返回-1

<5>  update(position,element):修改某个位置的元素

<6>  removeAt(position):从列表的特定位置移除一项

<7>  remove(element):从列表中移除一项

<8>  isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false

<9>  size():返回链表中包含的元素个数,与数组的length属性类似

<10>  toString():由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法。让其只输出元素的值

<11>  forwardString():返回正向遍历的节点字符串形式

<12>  backwardString():返回反向遍历的节点字符串的形式

 

双向链表方法的实现

1、toString、forwardString、backwardString方法实现

   //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0
        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }//toString方法
        DoublyLinkedList.prototype.toString = function () {
            return this.backwardString()
        }
        //forwardString
        DoublyLinkedList.prototype.forwardString = function () {
            //定义变量
            var current = this.tail
            var result = ''
            //依次向前遍历获取节点
            while(current){
                result += current.data + ' '
                current = current.prev
            }
            return result
        }
        //backwardString
        DoublyLinkedList.prototype.backwardString = function () {
            //定义变量
            var current = this.head
            var result = ''
            //依次向后遍历获取节点
            while(current){
                result += current.data + ' '
                current = current.next
            }
            return result
        }
    }

测试:

  //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.backwardString())
    alert(list.forwardString())

 

 

2、append方法的实现

 //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
            }
            //length加一
            this.length += 1
        }

测试:

   var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list)

 

 

3、insert方法的实现

    //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
         DoublyLinkedList.prototype.insert = function (position, data) {
            //越界判断
            if (position < 0 || position > this.length) return false
            //创建新的节点
            var newNode = new Node(data)
            //判断链表是否为空
            if (this.length == 0) {
                this.head = newNode
                this.tail = newNode
            } else {
                //第一种情况,判断prev是否为空。也就是原来有一个节点现在需要插入到节点的这个位置
                if (position == 0) {
                    this.head.prev = newNode   //原来的节点prev指向新节点
                    newNode.next = this.head    //新节点的next指向原来的节点
                    this.head = newNode    //head指向新节点
                } 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
            return true
        }
    }

 

测试:

 //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    list.insert(1,'aaa')
    list.insert(3,'bbb')
    list.insert(5,'ccc')
    alert(list)

 

4、get方法

  //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
           DoublyLinkedList.prototype.get = function (position) {
            //越界判断
            if (position < 0 || position >= this.length) return null
            //定义变量
            var index = 0
            var current = this.head
            while (index++ < position) {
                current = current.next
            }
            return current.data
        }
    }

测试:

 //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.get(2))

 

 

 这种方法查找的效率并不是很高,只能从前往后进行查找,如果此时链表的数据过多,那么就会使效率变低,所以进行判断,如果此时的链表长度除于2的结果大于position,就需要从后往前进行查找

所以此时需要这样写

  DoublyLinkedList.prototype.get = function (position) {
            //越界判断
            if (position < 0 || position >= this.length) return null
            if (this.length / 2 > position ) {
                //定义变量
                var index = 0
                var current = this.head
                while (index++ < position) {
                    current = current.next
                }
                return current.data
            } else{
                //定义变量
                var index = this.length
                var current = this.tail
                while (index-- < position) {
                    current = current.prev
                }
                return current.data
            }

        }

 

5、indexOf方法

    //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
     DoublyLinkedList.prototype.indexOf = function (data) {
            var current = this.head
            var index = 0
            while (current) {
                if (current.data == data) {
                    return index
                }
                current = current.next
                index++
            }
            return -1
        }
    }

测试:

//测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.indexOf('b'))
    alert(list.indexOf('d'))

 

 

 

 6、update方法

    //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
     DoublyLinkedList.prototype.update = function (position, newData) {
            //越界判断
            if (position < 0 || position >= this.length) return false
            //定义变量
            var curret = this.head
            var index = 0
            while (index++ < position) {
                current = curret.next
            }
            //修改data
            current.data=newData
            return true   //表示修改成功
        }
    }

测试:

    //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.update(1,'d'))
    alert(list)

 

 

 

还有一种思路跟get方法一样,进行判断,是否需要从后往前进行查找修改

DoublyLinkedList.prototype.update = function (position, newData) {
            //越界判断
            if (position < 0 || position >= this.length) return false
            if (this.length / 2 > position) {
                //定义变量
                var curret = this.head
                var index = 0
                while (index++ < position) {
                    current = curret.next
                }
                //修改data
                current.data=newData
                return true   //表示修改成功
            } else {
                //定义变量
                var curret = this.tail
                var index = this.length
                while (index-- < position) {
                    current = curret.prev
                }
                //修改data
                current.data=newData
                return true   //表示修改成功
            }

        }

 

 7、removeAt方法

 //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
     DoublyLinkedList.prototype.removeAt = function (position) {
            //越界判断
            if (position < 0 || position >= this.length) return null
            var current = this.head  //提到前面,便于获取删除的节点的data
            //第一种情况只有一个节点
            if (this.length == 1) {
                this.head = null
                this.tail = null
            } else {
                //第二种情况,长度不为1,删除第一个节点
                if (position == 0) {
                    this.head.next.prev = null
                    this.head = this.head.next
                } else if (position == this.length - 1) {
                    current = this.tail   //current指向尾部
                    //第三种情况,删除最后的节点
                    this.tail.prev.next = null
                    this.tail = this.tail.prev
                } else {
                    //第四种情况,在中间删除
                    var index = 0
                    while (index++ < position) {
                        current = current.next
                    }
                    current.prev.next = current.next
                    current.next.prev = current.prev
                }
            }
            //length减一
            this.length -= 1
            return current.data
        }
    }

测试:

    //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.removeAt(1))
    alert(list)

 

 

 8、remove方法

    //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
    DoublyLinkedList.prototype.indexOf = function (data) {
            var current = this.head
            var index = 0
            while (current) {
                if (current.data == data) {
                    return index
                }
                current = current.next
                index++
            }
            return -1
        }
      DoublyLinkedList.prototype.removeAt = function (position) {
            //越界判断
            if (position < 0 || position >= this.length) return null
            var current = this.head  //提到前面,便于获取删除的节点的data
            //第一种情况只有一个节点
            if (this.length == 1) {
                this.head = null
                this.tail = null
            } else {
                //第二种情况,长度不为1,删除第一个节点
                if (position == 0) {
                    this.head.next.prev = null
                    this.head = this.head.next
                } else if (position == this.length - 1) {
                    current = this.tail   //current指向尾部
                    //第三种情况,删除最后的节点
                    this.tail.prev.next = null
                    this.tail = this.tail.prev
                } else {
                    //第四种情况,在中间删除
                    var index = 0
                    while (index++ < position) {
                        current = current.next
                    }
                    current.prev.next = current.next
                    current.next.prev = current.prev
                }
            }
            //length减一
            this.length -= 1
            return current.data
        }
        DoublyLinkedList.prototype.remove = function (data) {
            //根据data获取索引
            var index = this.indexOf(data)
            //根据index删除对应位置的节点
            return this.removeAt(index)
        }
    }

测试:

 //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.remove('b'))
    alert(list)

 

 9、isEmpty、size方法

  //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
       DoublyLinkedList.prototype.isEmpty = function () {
            return this.length == 0
        }
        DoublyLinkedList.prototype.size = function () {
            return this.length
        }
    }

测试:

   //测试
    var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.isEmpty())
    alert(list.size())

 

 

 

10、获取链表的第一个元素、获取列表的最后一个元素

  //封装双向链表
    function DoublyLinkedList() {
        this.head = null
        this.tail = null
        this.length = 0

        //内部类,节点类
        function Node(data) {
            this.data = data
            this.prev = null
            this.next = null
        }
     DoublyLinkedList.prototype.getFirst = function () {
            return this.head.data
        }
     DoublyLinkedList.prototype.getLast = function () {
            return this.tail.data
        }
    }

测试:

 var list = new DoublyLinkedList()
    list.append('a')
    list.append('b')
    list.append('c')
    alert(list.getFirst())
    alert(list.getLast())

 

posted @ 2022-01-12 16:13  keyeking  阅读(97)  评论(0编辑  收藏  举报