Circular, doubly linked list, how to manage the node to object relationship?

大憨熊 提交于 2019-12-13 05:47:28

问题


This LinkedList function uses a very dodgy method to avoid client code needing to know about the linking nodes. Each list creates a unique string which is used to intrusively insert properties into the objects being added to the list. Does anyone know of a better way to do this? I should mention that removing objects in constant time is a requirement.

It does mean that client code looks like:

var myList = new LinkedList()

var a = new Something()
var b = new SomethingElse()

myList.addTail(a)
myList.addTail(b)

myList.remove(a)
myList.remove(b)

which is nice and readable, but the insertion of properties into the objects (which might clash with existing properties) is shaky, to say the least (although it can be documented and the property name prefix could be passed in to the LinkedList constructor).

This is the LinkedList code:

var LinkedList = (function() {

    var id = 0

    var Node = function(obj, p, n) {
        this.item = obj
        this.prev = p
        this.next = n
    }

    var list = function() {
        this.length = 0
        this.nodeName = '_' + id++ + 'lnn'
        this.root = new Node(null)
        this.root.next = this.root
        this.root.prev = this.root
    }

    list.prototype = {

        insertBefore : function(obj, item) {
            var node = new Node(item, obj.prev, obj)
            obj.prev.next = node
            obj.prev = node
            item[this.nodeName] = node
            ++this.length
        },

        insertAfter : function(obj, item) {
            var node = new Node(item, obj, obj.next)
            obj.next.prev = node
            obj.next = node
            item[this.nodeName] = node
            ++this.length
        },

        addTail : function(item) {
            this.insertBefore(this.root, item)
        },

        addHead : function(item) {
            this.insertAfter(this.root, item)
        },

        remove : function(item) {
            var node = item[this.nodeName]
            node.prev.next = node.next
            node.next.prev = node.prev
            delete node.item[this.nodeName]
            --this.length
        },

        popHead : function() {
            if(this.length > 0) {
                var node = this.root.next
                node.prev.next = node.next
                node.next.prev = node.prev
                delete node.item[this.nodeName]
                --this.length
                return node.item
            }
            return null
        },

        popTail : function() {
            if(this.length > 0) {
                var node = this.root.prev
                node.prev.next = node.next
                node.next.prev = node.prev
                delete node.item[this.nodeName]
                --this.length
                return node.item
            }
            return null
        },

        forEach : function(callback, context) {
            var node = this.root.next
            var index = 0
            while(node !== this.root) {
                var next = node.next
                if(callback.call(context, node.item, index) === false) {
                    return false
                }
                node = next
                ++index
            }
            return true
        },

        removeIf : function(callback, context) {
            var node = this.root.next
            while(node !== this.root) {
                var next = node.next
                if(callback.call(context, node.item) === true) {
                    node.prev.next = next
                    node.next.prev = node.prev
                    delete node.item[this.nodeName]
                    --this.length
                }
                node = next
            }
        },

        toString : function() {
            var s = this.length.toString()
            var sep = ':<'
            this.forEach(function(i, index) {
                s += sep + i.toString()
                sep = ','
            })
            return s + '>'
        }
    }

    return list
})()

回答1:


Here's my implementation:

function LinkedList(initialValues){
  var head = null,
    version = 0,
    list = {
      push: function(){
        var args = [].slice.call(arguments, 0),
          pushable = null;
        while(args.length && (pushable = args.shift()))
          head = new Node(pushable).append(head);
        version++;
        return this;
      },
      pop: function(){
        var popped = head;
        head = head.next();
        version++;
        return popped.value();
      },
      peek: function(){
        return head && head.value();
      },
      iterator: function(){
        return new Iterator(head, version);
      },
      toString: function(){
        var vals = [],
          iter = new Iterator(head, version);
        while(iter.node()){
          vals.push(iter.node().toString());
          iter.step();
        }
        return ["("].concat(vals).concat(")").join(" ");
      },
      size: function(){
        var iter = new Iterator(head, version);
        while(iter.node()){
          iter.step();
        }
        return iter.index();
      }
    };
  return list.push.apply(list, initialValues);

  function Node(input){
    var content = input,
      next = null;
    return {
      next: function(){
        return next;
      },
      value: function(){
        return content;
      },
      append: function(node){
        next = node;
        return this;
      },
      set: function(val){
        return content = val;
      },
      toString: function(){
        return content.toString();
      }
    };
  }

  function Iterator(base, v){
    var current = base, index = 0,
      checkSafe = function(){
        if(v === version)
          return true;
        else
          throw "The iterator is no longer valid, list modified.";
      };
    return {
      node: function(){
        checkSafe();
        return current;
      },
      step: function(){
        checkSafe();
        current = current.next();
        index++;
        return this;
      },
      index: function(){
        checkSafe();
        return index;
      }
    };
  }
}


来源:https://stackoverflow.com/questions/22108378/circular-doubly-linked-list-how-to-manage-the-node-to-object-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!