sapitando

circularLinkedList.js

Apr 20th, 2022 (edited)
378
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function LinkedList() {
  2.   "use strict";
  3.  
  4.   this.meta = {
  5.     current: {
  6.       address: undefined,
  7.       position: -1,
  8.     },
  9.     list: {
  10.       length: 0,
  11.       nodesCreated: 0, // debug
  12.       nodesDeleted: 0, // debug
  13.       first: undefined,
  14.       get last() { return this.first?.pointers.previousNode; },
  15.     },
  16.   };
  17.   this.add          = addNodeFn(this);
  18.   this.addNodes     = addMultipleNodesFn(this);
  19.   this.append       = appendNodeFn(this);
  20.   this.appendNodes  = appendMultipleNodesFn(this);
  21.   this.prepend      = prependNodeFn(this);
  22.   this.prependNodes = prependMultipleNodesFn(this);
  23.   this.delete       = deleteNodeFn(this);
  24.   this.deleteNodes  = deleteMultipleNodesFn(this);
  25.   this.trimStart    = trimStartMultipleNodesFn(this);
  26.   this.trimEnd      = trimEndMultipleNodesFn(this);
  27.   this.node         = getNodeFn(this);
  28.   this.previous     = previousNodeFn(this);
  29.   this.next         = nextNodeFn(this);
  30.   this.jump         = jumpMultipleNodesFn(this);
  31.   this.at           = atNodeFn(this);
  32.   this.setFirst     = setFirstNodeFn(this);
  33.  
  34.   Object.defineProperty(this, 'data',
  35.   { get: function() { return this.meta.current.address?.content.data; },
  36.     set: function(data) {
  37.       if (this.meta.current.address) this.meta.current.address.content.data = data; } });
  38.   Object.defineProperty(this, 'info', { get: function() {
  39.     console.log(`Length: ${ this.meta.list.length }\nCreated Nodes: ${ this.meta.list.nodesCreated }\nDeleted Nodes: ` +
  40.       `${ this.meta.list.nodesDeleted }\nCurrent Position: ${ this.meta.current.position }`); return; } });
  41.  
  42.   function addNodeFn(anchor) {
  43.     const current = anchor.meta.current;
  44.     const list    = anchor.meta.list;
  45.     let previousNode;
  46.     let nextNode;
  47.     return function (data) {
  48.       const currentNode = {
  49.         pointers: {},
  50.         content: { data },
  51.         get data() { return this.content.data; },
  52.         set data(data) { this.content.data = data; },
  53.         get 'list-position'() { return current.position; },
  54.         get 'list-position(debug)'() { return getLocationNode(anchor, currentNode)(); }, //debug
  55.       };
  56.       if (list.length) {
  57.         previousNode = current.address;
  58.         nextNode = current.address.pointers.nextNode;
  59.       } else {
  60.         previousNode = nextNode = list.first = currentNode;
  61.       }
  62.       currentNode.pointers.previousNode = previousNode;
  63.       currentNode.pointers.nextNode = nextNode;
  64.       nextNode.pointers.previousNode = currentNode;
  65.       previousNode.pointers.nextNode = currentNode;
  66.       copyMethodsFn(currentNode, anchor);
  67.       list.nodesCreated++; // debug
  68.       list.length++;
  69.       current.position++;
  70.       return (current.address = currentNode);
  71.     };
  72.   }
  73.  
  74.   function appendNodeFn(anchor) {
  75.     const current = anchor.meta.current;
  76.     const list    = anchor.meta.list;
  77.     return function (data) {
  78.       current.address = list.last;
  79.       current.position = list.length - 1;
  80.       return addNodeFn(anchor)(data);
  81.     };
  82.   }
  83.  
  84.   function prependNodeFn(anchor) {
  85.     const current = anchor.meta.current;
  86.     const list    = anchor.meta.list;
  87.     return function (data) {
  88.       current.address = list.last;
  89.       current.position = -1;
  90.       return (list.first = addNodeFn(anchor)(data));
  91.     };
  92.   }
  93.  
  94.   function addMultipleNodesFn(anchor) {
  95.     const current = anchor.meta.current;
  96.     return function (...args) {
  97.       switch (parseArgumentsFn(...args)) {
  98.         case 'empty':
  99.           args[0] = 1;
  100.         case 'number':
  101.           while (args[0]--) { addNodeFn(anchor)(); }
  102.           break;
  103.         case 'array':
  104.           args.reverse();
  105.           while (args.length) { addNodeFn(anchor)(args.pop()); }
  106.       }
  107.       return current.address;
  108.     };
  109.   }
  110.  
  111.   function appendMultipleNodesFn(anchor) {
  112.     const current = anchor.meta.current;
  113.     const list    = anchor.meta.list;
  114.     return function (...args) {
  115.       current.address = list.last;
  116.       current.position = list.length - 1;
  117.       return addMultipleNodesFn(anchor)(...args);
  118.     };
  119.   }
  120.  
  121.   function prependMultipleNodesFn(anchor) {
  122.     const current = anchor.meta.current;
  123.     const list    = anchor.meta.list;
  124.     const pinpoint = saveCurrentStateFn(anchor);
  125.     return function (...args) {
  126.       pinpoint(true);
  127.       current.address = list.last;
  128.       current.position = -1;
  129.       addMultipleNodesFn(anchor)(...args);
  130.       list.first = pinpoint('after-last');
  131.       return current.address;
  132.     };
  133.   }
  134.  
  135.   function parseArgumentsFn(...args) {
  136.     switch (args.length) {
  137.       case 0:
  138.         return 'empty';
  139.       case 1:
  140.         if (isNaturalNumber(args[0])) { return 'number'; }
  141.       default:
  142.         return 'array';
  143.     }
  144.   }
  145.  
  146.   function deleteNodeFn(anchor) {
  147.     const list = anchor.meta.list;
  148.     return function () {
  149.     if (!list.length) { return undefined; }
  150.     return removeNodeFn(anchor, false);
  151.     };
  152.   }
  153.  
  154.   function deleteMultipleNodesFn(anchor) {
  155.     const current = anchor.meta.current;
  156.     const list    = anchor.meta.list;
  157.     return function (amount) {
  158.       if (list.length && isNaturalNumber(amount)) {
  159.         removeMultipleNodesFn(anchor, amount, true);
  160.         return current.address;
  161.       }
  162.       return undefined;
  163.     };
  164.   }
  165.  
  166.   function trimStartMultipleNodesFn(anchor) {
  167.     const current = anchor.meta.current;
  168.     const list    = anchor.meta.list;
  169.     return function (amount) {
  170.       if (!arguments.length) amount = 1;
  171.       if (list.length && isNaturalNumber(amount)) {
  172.         current.address = list.first;
  173.         current.position = 0;
  174.         removeMultipleNodesFn(anchor, amount, true);
  175.         return current.address;
  176.       }
  177.       return undefined;
  178.     };
  179.   }
  180.  
  181.   function trimEndMultipleNodesFn(anchor) {
  182.     const current = anchor.meta.current;
  183.     const list    = anchor.meta.list;
  184.     return function (amount) {
  185.       if (!arguments.length) amount = 1;
  186.       if (list.length && isNaturalNumber(amount)) {
  187.         current.address = list.last;
  188.         current.position = list.length - 1;
  189.         removeMultipleNodesFn(anchor, amount, false);
  190.         return current.address;
  191.       }
  192.       return undefined;
  193.     };
  194.   }
  195.  
  196.   function removeNodeFn(anchor, passThrough) {
  197.     const current = anchor.meta.current;
  198.     const list    = anchor.meta.list;
  199.     let disconectedNode = disconectNodeFn(current.address);
  200.     [current.address, current.position, list.first] =
  201.       getNewStateFn(current.address, current.position, list.first, passThrough);
  202.     deleteAllNodeProperties(disconectedNode);
  203.     list.length--;
  204.     list.nodesDeleted++; // debug
  205.     return current.address;
  206.   }
  207.  
  208.   function removeMultipleNodesFn(anchor, amount, passThrough) {
  209.     const current = anchor.meta.current;
  210.     const list    = anchor.meta.list;
  211.     amount = amount > list.length ? list.length : amount;
  212.     while (amount--) removeNodeFn(anchor, passThrough);
  213.     return current.address;
  214.   }
  215.  
  216.   function disconectNodeFn(node) {
  217.     const previousNode = node.pointers.previousNode;
  218.     const nextNode = node.pointers.nextNode;
  219.     previousNode.pointers.nextNode = nextNode;
  220.     nextNode.pointers.previousNode = previousNode;
  221.     return node;
  222.   }
  223.  
  224.   function getNewStateFn(address, position, first, passThrough = false) {
  225.     switch (true) {
  226.     case (address === first && address.pointers.previousNode === first):
  227.       address = first = undefined;
  228.       position = -1 ;
  229.       break;
  230.     case (address === first):
  231.       address = first = first.pointers.nextNode;
  232.       break;
  233.     case (address.pointers.nextNode === first):
  234.       switch (passThrough) {
  235.       case (true):
  236.         position = 0;
  237.         address = address.pointers.nextNode;
  238.         break;
  239.       case (false):
  240.         position--;
  241.         address = address.pointers.previousNode;
  242.         break;
  243.       }
  244.       break;
  245.     default:
  246.       address = address.pointers.nextNode;
  247.     }
  248.     return [address, position, first];
  249.   }
  250.  
  251.   function deleteAllNodeProperties(node) {
  252.     let result = true;
  253.     result = (delete node['list-position']) && result;
  254.     result = (delete node['list-position(debug)']) && result;
  255.     result = (delete node.content.data) && result;
  256.     result = (delete node.content) && result;
  257.     result = (delete node.data) && result;
  258.     result = (delete node.pointers.previousNode) && result;
  259.     result = (delete node.pointers.nextNode) && result;
  260.     result = (delete node.pointers) && result;
  261.     result = (delete node.add) && result;
  262.     result = (delete node.addNodes) && result;
  263.     result = (delete node.append) && result;
  264.     result = (delete node.appendNodes) && result;
  265.     result = (delete node.prepend) && result;
  266.     result = (delete node.prependNodes) && result;
  267.     result = (delete node.delete) && result;
  268.     result = (delete node.deleteNodes) && result;
  269.     result = (delete node.trimStart) && result;
  270.     result = (delete node.trimEnd) && result;
  271.     result = (delete node.node) && result;
  272.     result = (delete node.previous) && result;
  273.     result = (delete node.next) && result;
  274.     result = (delete node.jump) && result;
  275.     result = (delete node.at) && result;
  276.     result = (delete node.setFirst) && result;
  277.     return result;
  278.   }
  279.  
  280.   function setFirstNodeFn(anchor) {
  281.     const current = anchor.meta.current;
  282.     const list    = anchor.meta.list;
  283.     return function (node) {
  284.       let condition = Boolean(node) && typeof node === 'object' && 'pointers' in node;
  285.       return arguments.length && !condition ?
  286.         undefined : (list.first = condition ? (current.address = node) : current.address);
  287.     };
  288.   }
  289.  
  290.   function getNodeFn(anchor) {
  291.     const current = anchor.meta.current;
  292.     return function () {
  293.       return current.address;
  294.     };
  295.   }
  296.  
  297.   function nextNodeFn(anchor) {
  298.     const current = anchor.meta.current;
  299.     const list    = anchor.meta.list;
  300.     return function () {
  301.       if (!list.length) {
  302.         return undefined;
  303.       }
  304.       current.position = (current.position + 1) % list.length;
  305.       return (current.address = current.address.pointers.nextNode);
  306.     };
  307.   }
  308.  
  309.   function previousNodeFn(anchor) {
  310.     const current = anchor.meta.current;
  311.     const list    = anchor.meta.list;
  312.     return function () {
  313.       if (!list.length) {
  314.         return undefined;
  315.       }
  316.       current.position = (current.position || list.length) - 1;
  317.       return (current.address = current.address.pointers.previousNode);
  318.     };
  319.   }
  320.  
  321.   function jumpMultipleNodesFn(anchor) {
  322.     const list = anchor.meta.list;
  323.     return function (jumps) {
  324.       const condition = Boolean(list.length) && Number.isFinite(jumps);
  325.       return condition ? loopThroughMultipleNodesFn(anchor, jumps) : undefined;
  326.     };
  327.   }
  328.  
  329.   function atNodeFn(anchor) {
  330.     const list = anchor.meta.list;
  331.     return function (destination) {
  332.       const condition = Boolean(list.length) &&
  333.         Number.isFinite(destination) &&
  334.         (destination < 0 ? ~destination : destination) < list.length;
  335.       if (condition) {
  336.         let jumps = getJumpsToDestinationFn(anchor, destination);
  337.         return loopThroughMultipleNodesFn(anchor, jumps);
  338.       }
  339.       return undefined;
  340.     };
  341.   }
  342.  
  343.   function getJumpsToDestinationFn(anchor, destination) {
  344.     const current = anchor.meta.current;
  345.     const list    = anchor.meta.list;
  346.     let jumps = destination >= 0 ? destination - current.position :
  347.       list.length + destination - current.position;
  348.     return jumps;
  349.   }
  350.  
  351.   function getDestinationFromJumpsFn(anchor, jumps) {
  352.     const current = anchor.meta.current;
  353.     const list    = anchor.meta.list;
  354.     let destination = jumps >= 0 ? (current.position + jumps) % list.length :
  355.       list.length - 1 - (list.length - 1 - current.position - jumps) % list.length;
  356.     return destination;
  357.   }
  358.  
  359.   function getShortPathFn(anchor, jumps) {
  360.     const current = anchor.meta.current;
  361.     const list    = anchor.meta.list;
  362.     const destination = getDestinationFromJumpsFn(anchor, jumps);
  363.     const jumpsFromStart    = destination;
  364.     const jumpsFromEnd      = destination - (list.length - 1);
  365.     const JumpsFromPosition = destination - current.position;
  366.    
  367.     const fromStart = jumpsFromStart <= Math.abs(jumpsFromEnd)
  368.                       && jumpsFromStart <= Math.abs(JumpsFromPosition);
  369.                                        
  370.     const fromEnd   = Math.abs(jumpsFromEnd) <= jumpsFromStart
  371.                       && Math.abs(jumpsFromEnd) <= Math.abs(JumpsFromPosition);
  372.     let address;
  373.     switch (true) {
  374.     case fromStart:
  375.       address = list.first;
  376.       jumps = jumpsFromStart;
  377.       break;
  378.     case fromEnd:
  379.       address = list.last;
  380.       jumps = jumpsFromEnd;
  381.       break;
  382.     default:
  383.       address = current.address;
  384.       jumps = JumpsFromPosition;
  385.       break;
  386.     }
  387.     console.log( `Starting from ${
  388.       fromStart ? `begin: 0` :
  389.       fromEnd ? `end: ${list.length - 1}` :
  390.                 `current position: ${ current.position }` }` +
  391.       `\nJumps: ${ jumps }\nDestination: ${ destination }` ); // debug
  392.     return [address, jumps, destination];
  393.   }
  394.  
  395.   function loopThroughMultipleNodesFn(anchor, jumps, shortcut = true) {
  396.     const current = anchor.meta.current;
  397.     let destination;
  398.     if (shortcut) {
  399.       [current.address, jumps, destination] = getShortPathFn(anchor, jumps);
  400.     } else {
  401.       destination = getDestinationFromJumpsFn(anchor, jumps);
  402.     }
  403.     switch (true) {
  404.     case (jumps > 0):
  405.       while (jumps--) current.address = current.address.pointers.nextNode;
  406.       break;
  407.     case (jumps < 0):
  408.       while (jumps++) current.address = current.address.pointers.previousNode;
  409.       break;
  410.     }
  411.     current.position = destination;
  412.     return current.address;
  413.   }
  414.  
  415.   function copyMethodsFn(toObject, fromObject) {
  416.     toObject.add          = fromObject.add;
  417.     toObject.addNodes     = fromObject.addNodes;
  418.     toObject.append       = fromObject.append;
  419.     toObject.appendNodes  = fromObject.appendNodes;
  420.     toObject.prepend      = fromObject.prepend;
  421.     toObject.prependNodes = fromObject.prependNodes;
  422.     toObject.delete       = fromObject.delete;
  423.     toObject.deleteNodes  = fromObject.deleteNodes;
  424.     toObject.trimStart    = fromObject.trimStart;
  425.     toObject.trimEnd      = fromObject.trimEnd;
  426.     toObject.node         = fromObject.node
  427.     toObject.previous     = fromObject.previous;
  428.     toObject.next         = fromObject.next;
  429.     toObject.jump         = fromObject.jump;
  430.     toObject.at           = fromObject.at;
  431.     toObject.setFirst     = fromObject.setFirst;
  432.     return undefined;
  433.   }
  434.  
  435.   function isNaturalNumber(number) {
  436.     return (Number.isInteger(number) && number > 0);
  437.   }
  438.  
  439.   function saveCurrentStateFn(anchor) {
  440.     const replica = {
  441.       current: {},
  442.       list: {},
  443.     };
  444.     return function (condition = false) {
  445.       switch (condition) {
  446.       case 'current':
  447.         return replica.current;
  448.       case 'list':
  449.         return replica.list;
  450.       case 'after-last':
  451.         return replica.list.last?.pointers.nextNode || anchor.meta.list.first;
  452.       case (true):
  453.         replica.current.address  = anchor.meta.current.address;
  454.         replica.current.position = anchor.meta.current.position;
  455.         replica.list.length      = anchor.meta.list.length;
  456.         replica.list.first       = anchor.meta.list.first;
  457.         replica.list.last        = anchor.meta.list.last;
  458.       case (false):
  459.         return replica;
  460.       }
  461.       return undefined;
  462.     };
  463.   }
  464.  
  465.  
  466.   /* Functions for debug */
  467.  
  468.   function getLocationNode(anchor, currentNode) {
  469.     const list = anchor.meta.list;
  470.     return function () {
  471.       let counter;
  472.       for (counter = 0; currentNode !== list.first; counter++) {
  473.         currentNode = currentNode.pointers.previousNode;
  474.       }
  475.       return counter;
  476.     };
  477.   }
  478.  
  479. }
  480.  
  481. /* const obj = new LinkedList(); */
  482.  
Add Comment
Please, Sign In to add comment