Реализация n-арного дерева в javascript через связанный список - PullRequest
0 голосов
/ 17 мая 2018
  • Проблема: есть ли способ использовать TreeListNode в Tree.insert (элемент)?Ограничение состоит в том, что singleLinkedList.addToTail (element) принимает элемент и возвращает ListNode, у которого нет атрибутов 'children' и 'parent', и если я сначала создам TreeListNode (element), то я не смог бы использовать singleLinkedList.addToTail (element).

  • Контекст: я изучаю структуры данных в javascript.Уже реализовав LinkedList и Queues, я сейчас пытаюсь использовать их как библиотеку для реализации n-арного дерева с обходами в глубину и в ширину. Благодаря этому я также пытаюсь изучить лучшие практики javascript.Любой, кто может предложить дополнительные советы о том, как улучшить мой код, получит мою вечную благодарность.Является ли шаблон, которому я следовал (в отношении использования объектов Position, ListNode и TreeListNode), в порядке?Правильно ли я следовал «составлению по наследованию»?

Вот моя реализация дерева:

const Queue = require('./queue.js')
const LinkedListLibrary = require('./linkedListTest.js');

function TreeNode(element){
    LinkedListLibrary.ListNode.call(this, element);
    this.parent = null;
    this.children = new LinkedListLibrary.SingleLinkedList() 
}

TreeNode.prototype = Object.create(LinkedListLibrary.ListNode.prototype)

function Tree(rootElement){
    this._root = new TreeNode(rootElement);     
    this._size = 1;
};

Tree.prototype = {

    isEmpty: function() {
        return (this._size == 0)
    //Returns true if the tree is empty. True only initially
    },

    size: function() {
        return this._size
    // Returns the number of nodes in the tree. 
    },

    getRoot: function(){
        //console.log("Entered getRoot function");
        return this._root
    },

    traverseDF: function(callback){
    // This method traverses a tree with depth-first search.
        (function recurse(currentNode){ //Step 2    
            for (var i = 0; i < currentNode.children.length; i++){
                recurse(currentNode.children.getNode(i)) //Step 3. When currentNode = leaf, length = 0
        };
        //console.log("Traversed the children of: " + JSON.stringify(currentNode.getElement()));
        callback(currentNode) //Step 4

    })(this.getRoot()) //Step 1. Immediate Invoke Recurse with the root node as argument

    },

    traverseBF: function(callback){
        var bfQueue = new Queue();
        bfQueue.enqueue(this.getRoot());
        while(!bfQueue.isEmpty()){   
            console.log("Next element to dequeue:" + bfQueue._head.data.getElement())
            var currentTreeNode = bfQueue.dequeue();
            console.log("currentTreeNode contains " + currentTreeNode.getElement())
            callback(currentTreeNode)
            for (var i = 0; i < currentTreeNode.children.length; i++){
                var temp = currentTreeNode.children.getNode(i);
                console.log("enqueing: " + JSON.stringify(temp.getElement()))
                bfQueue.enqueue(temp);

            }

        }

    },

    insert: function(element, toElement, traversal) {
        //Adds a node to a tree.
        console.log("Inserting element: " + element)
        var parent = null
        var callback = function(node){
        //console.log("Now comparing: " + node.getElement())
            if (node.getElement() === toElement ){
                //console.log(JSON.stringify("Found parent: " + node.getElement())   );
                parent = node;
            }
        }
        traversal.call(this, callback);

        if(parent){
            //console.log("Adding to tail: " + JSON.stringify(data));
            var childrenList = parent.children
            childrenList.addToTail(element);
            var newChild = childrenList.getNode(childrenList.length-1)
            newChild.parent = parent;
            //console.log(JSON.stringify("Added new child to " + parent.getElement() + " with element " + newChild.getElement())  );
        } else {
            throw new Error('cannot add node to a non-existent parent')
          }

     }

Вот реализация LinkedList:

module.exports = { Position, ListNode, SingleLinkedList} 

function Position(element){
    this._element = element
}

Position.prototype.getElement = function(){
    return this._element
}   

function ListNode(element, next){
    this.next = next,
    Position.call(this, element)
}

ListNode.prototype = Object.create(Position.prototype)

function SingleLinkedList(){
    this.head =  null;  
    this.length = 0;
}

SingleLinkedList.prototype = {

    addToHead : function(element){
        var newHead = new ListNode(element, this.head);
        this.head = newHead;
        this.length++
    },

    addToTail : function(element){
        var newNode = new ListNode(element, null);
        if (this.head === null){
            //console.log("Head not found, adding to head")
            this.head = newNode;
            this.length++;
        return;
       }
       var current_node = this.head;
       while(!(current_node.next === null)){
           current_node = current_node.next
       }
        current_node.next = newNode;
        this.length++
    },

    getNode : function(position){
        if (position >= this.length) {
            console.log("Position out of bounds")
        }
        var nodeToCheck = this.head;
        //console.log("Checking node: " + nodeToCheck.getElement())
        var i = 0;
        while(i != position) {
            nodeToCheck = nodeToCheck.next;
            //console.log("New nodeToCheck: " + nodeToCheck.getElement())
            i++;
        }
        return nodeToCheck;
    }
}
...