From 316210549c9582fed2e21572c84e4d7f2fc1262e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Mon, 15 May 2017 11:12:51 -0700 Subject: [PATCH 01/38] Initial commit --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 74e5c30..82ee366 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,15 @@ Tests and implementations for common data structures. See the full list in the [data-structures.md](data-structures.md) file. -Base repository for the [Core Data Structures](http://jsdev.learnersguild.org/goals/128) goal. +Project Goal: [Core Data Structures - Basic] (http://jsdev.learnersguild.org/goals/156-Core_Data_Structures-Basic.html) + +Base repository for the [Core Data Structures](Core Data Structures--Basic) goal. + +Team Name: ten-seal + +Project Members: +[Jonathan Pool](https://github.com/jrpool) +[Fodé Diop](https://github.com/diop) ## Installation and Setup From 7cc5606d79beccc909eb7ce70fd1f4b85e08068b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Mon, 15 May 2017 11:14:58 -0700 Subject: [PATCH 02/38] Fix README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82ee366..2bc135c 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,16 @@ Tests and implementations for common data structures. See the full list in the [data-structures.md](data-structures.md) file. -Project Goal: [Core Data Structures - Basic] (http://jsdev.learnersguild.org/goals/156-Core_Data_Structures-Basic.html) +Project Goal: [Core Data Structures - Basic](http://jsdev.learnersguild.org/goals/156-Core_Data_Structures-Basic.html) Base repository for the [Core Data Structures](Core Data Structures--Basic) goal. Team Name: ten-seal Project Members: + [Jonathan Pool](https://github.com/jrpool) + [Fodé Diop](https://github.com/diop) ## Installation and Setup From 7e0175353059ac7233b7c70ff2fd818f661e4e00 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Mon, 15 May 2017 13:57:57 -0700 Subject: [PATCH 03/38] Added installation and setup to README file and deleted advanced section from data-structures file. --- README.md | 22 ++++++++++++- data-structures.md | 81 ---------------------------------------------- 2 files changed, 21 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index 2bc135c..e0ba10b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,27 @@ Project Members: ## Installation and Setup -_Fill this out_ +0. These instructions presuppose that npm (https://nodejs.org/en/) is installed. + +1. Clone this repository into a local directory. + +2. In the local directory, install required dependencies (see package.json) by executing: + + npm i + +3. In the local directory, perform the provided tests by executing: + + npm test + +4. Install ESLint (http://eslint.org) by executing: + + npm install -gS eslint + + cd + + eslint --init + +5. Edit .eslintrc.json in your home directory to customize. ## Usage and Examples diff --git a/data-structures.md b/data-structures.md index 7b2e43d..8ea46d0 100644 --- a/data-structures.md +++ b/data-structures.md @@ -156,87 +156,6 @@ set.clone() // returns a cloned set. _Note: if you haven't worked with sets before, you may want to read about [sets](https://www.mathsisfun.com/sets/sets-introduction.html) and [subsets](https://www.mathsisfun.com/activity/subsets.html)._ -## Advanced Data Structures - -### Hash Table ( using a LinkedList for collision chaining ) - -Maps keys to values, like a dictionary or a phone book. Or an object in JavaScript... - -From [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) [edited]: - -> A data structure used to implement an associative array, a structure that can map keys to values. A hash table uses a hash function to compute an index into an array of _buckets_ or _slots_, from which the desired value can be found. - -Collision Chaining: [Wikipedia](http://www.cs.rmit.edu.au/online/blackboard/chapter/05/documents/contribute/chapter/05/chaining.html) -> Instead of storing the data directly inside the structure, have a linked list structure at each hash element. That way, all the collision, retrieval and deletion functions can be handled by the list, and the hash function's role is limited mainly to that of a guide to the algorithms, as to which hash element's list to operate on. - -```javascript -const ht = new HashTable() -ht.put("name", "Zanzibar") // adds a key-value pair to the hash table, deal with collisions using chaining -ht.get("name") // returns the data associated with key. -ht.contains("name") // returns true if the hash table contains the key. -ht.iterate((k, v) => console.log(`${k}: ${v}`)) // takes a callback function and passes it each key and value in sequence. -ht.remove("name") // removes a key-value pair by key. -ht.size() // returns the number of key-value pairs in the hash table. -HashTable.hash("name") // generates a hash for the key "name" -``` - -### Binary (Search) Tree - -A sorted binary tree for fast lookup, addition and removal of items. - -From [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_tree) [edited]: - -> A particular type of container that allows fast lookup, addition and removal of items, and can be used to implement either dynamic sets of items, or lookup tables that allow finding an item by its key (e.g., finding the phone number of a person by name). -> -> Binary search trees keep their keys in sorted order, so that lookup and other operations can use the principle of binary search: when looking for a key in a tree (or a place to insert a new key), they traverse the tree from root to leaf, making comparisons to keys stored in the nodes of the tree and deciding, based on the comparison, to continue searching in the left or right subtrees. - -```javascript -const bst = new BinarySearchTree() -bst.insert(3) // inserts a node with the specified value into the tree. -bst.search(3) // returns a node object or null if not found. -bst.remove(3) // removes an value's node (if exists) from the tree. -bst.traverse((val) => console.log(val)) // traverse the tree using in-order traversal and apply function on each node's value. -bst.count() // return the number of nodes in the tree. -``` - -#### Tree Node - -To implement a _standard_ binary search tree, use a **tree node** data structure in your implementation. Use this interface as a reference: - -```javascript -const leastNode = new TreeNode({data: 3}) -const moreNode = new TreeNode({data: 10}) -const midNode = new TreeNode({data: 7, left: leastNode, right: moreNode}) - -midNode.getData() // returns the node's data -midNode.getLeft() // returns the left node or null if none -midNode.setLeft(leastNode) // changes the reference to the left node and returns the original node -midNode.getRight() // returns the right node or null if none -midNode.setRight(moreNode) // changes the reference to the right node and returns the original node -``` - -### Directed Graph - -Nodes connected by vertices with a direction. - -From [Wikipedia](https://en.wikipedia.org/wiki/Directed_graph) [edited]: - -> A graph (that is a set of vertices connected by edges), where the edges have a direction associated with them. - -```javascript -const diGraph = new DirectedGraph() -diGraph.addVertex('v1') // adds a vertex to the graph. -diGraph.hasVertex('v1') // returns true if the graph contains the vertex or false if not. -diGraph.addDirection('v1', 'v2') // adds a direction from 'v1' to 'v2'. -diGraph.hasDirection('v1', 'v2') // returns true if there's a direction from 'v1' to 'v2'. -diGraph.visit('v1', vertex => console.log(vertex)) // visit all the connected vertices in the graph starting with v1 and apply function on the reached vertex. -diGraph.findPaths('v1', 'v2') // returns an array of all the paths between two vertices. -diGraph.removeDirection('v1', 'v2') // removes an existing direction between 'v1' and 'v2'. -diGraph.getSeparatedVertices() // returns an array of all the vertices that are unconnected to the graph (have no direction linking them to another vertex). -diGraph.removeVertex('v1') // removes an existing vertex and all its directions (the incoming and outgoing). -diGraph.count() // returns the number of vertices in the graph. -``` - ### Sources Most of the above was shamelessly borrowed from Wikipedia and these libraries: From 99dafb767910699a650cc02c717c556d5970e305 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Mon, 15 May 2017 17:03:17 -0700 Subject: [PATCH 04/38] Wrote and began testing PriorityNode class. --- .gitignore | 1 + package.json | 15 +++++++++--- spec/priority_node.js | 23 ++++++++++++++++++ spec/{stack.js => stack.js-template} | 0 src/priority_node.js | 36 ++++++++++++++++++++++++++++ src/{stack.js => stack.js-template} | 0 6 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 spec/priority_node.js rename spec/{stack.js => stack.js-template} (100%) create mode 100644 src/priority_node.js rename src/{stack.js => stack.js-template} (100%) diff --git a/.gitignore b/.gitignore index c2658d7..2752eb9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +.DS_Store diff --git a/package.json b/package.json index d47a351..158a12c 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,24 @@ { "name": "core-data-structures", - "description": "Tests and implementations for common data structures.", + "description": "Tests and implementations for basic core data structures.", "private": false, "version": "0.0.0", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/diop/core-data-structures" + }, + "dependencies": { + "babel-preset-es2015": "^6.24.1", + "babel-register": "^6.24.1" + }, "devDependencies": { "babel-cli": "^6.18.0", "babel-preset-env": "^1.1.4", "babel-register": "^6.18.0", - "chai": "~1.8.0", + "chai": "^1.8.1", "chai-change": "^2.1.2", - "mocha": "2.0.1" + "mocha": "^2.0.1" }, "scripts": { "build": "babel src -d lib", diff --git a/spec/priority_node.js b/spec/priority_node.js new file mode 100644 index 0000000..73eb5d1 --- /dev/null +++ b/spec/priority_node.js @@ -0,0 +1,23 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import PriorityNode from '../src/priority_node' + +chai.use(chaiChange) + +describe('PriorityNode', () => { + 'use strict' + + it('is a function', () => { + expect(PriorityNode).to.be.a('function') + }) + + context('getData()', () => { + it('returns a string when given detData().', () => { + const levelZero = new PriorityNode( + {data: "level0", priority: 0} + ) + const data = levelZero.getData() + expect(data).to.be.a('string') + }) + }) +}) diff --git a/spec/stack.js b/spec/stack.js-template similarity index 100% rename from spec/stack.js rename to spec/stack.js-template diff --git a/src/priority_node.js b/src/priority_node.js new file mode 100644 index 0000000..4bf3de5 --- /dev/null +++ b/src/priority_node.js @@ -0,0 +1,36 @@ +'use strict' + +/* + Class declaration for PriorityNode and export statement making that + object the default export from this module. +*/ +export default class PriorityNode { + constructor(nodeProps) { + this.data = nodeProps.data; + this.priority = nodeProps.priorty; + this.next = nodeProps.next; + } + // Returns the node’s data. + getData() { + return this.data; + } + // Returns the node’s priority. + getPriority() { + return this.priority; + } + // Returns the next node, or null if none. + getNext() { + return this.next || null; + } + // Changes the node’s priority and returns the post-change node. + setPriority(newPriority) { + this.priority = newPriority; + return this; + } + // Changes the next node and returns the pre-change node. + setNext(newNext) { + const origThis = this; + this.next = newNext; + return origThis; + } +} diff --git a/src/stack.js b/src/stack.js-template similarity index 100% rename from src/stack.js rename to src/stack.js-template From 974bf6c8521699b633314f6d091a6741fd2e9675 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Mon, 15 May 2017 18:05:11 -0700 Subject: [PATCH 05/38] Added tests and organized them into contexts. --- spec/priority_node.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/spec/priority_node.js b/spec/priority_node.js index 73eb5d1..74ed6d2 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -12,12 +12,25 @@ describe('PriorityNode', () => { }) context('getData()', () => { - it('returns a string when given detData().', () => { - const levelZero = new PriorityNode( - {data: "level0", priority: 0} - ) + it('returns the correct type, if string', () => { + const levelZero = new PriorityNode({data: "level0", priority: 0}) const data = levelZero.getData() expect(data).to.be.a('string') }) + it('returns the correct value, if a string', () => { + const levelZero = new PriorityNode({data: "level0", priority: 0}) + const data = levelZero.getData() + expect(data).to.be.equal('level0') + }) + it('returns the correct type, if number', () => { + const levelZero = new PriorityNode({data: 0, priority: 0}) + const data = levelZero.getData() + expect(data).to.be.a('number') + }) + it('returns the correct value, if a number', () => { + const levelZero = new PriorityNode({data: 0, priority: 0}) + const data = levelZero.getData() + expect(data).to.be.equal(0) + }) }) }) From 4c1716ef497216ecbdc988f0bac872a0c2108ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Mon, 15 May 2017 23:24:04 -0700 Subject: [PATCH 06/38] add node class --- src/node.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/node.js diff --git a/src/node.js b/src/node.js new file mode 100644 index 0000000..76e2d7b --- /dev/null +++ b/src/node.js @@ -0,0 +1,36 @@ +// Node -- A very basic data structure that can contain some value and a reference to another node. +function Node(data, next){ + this.data = data; + this.next = next; +}; + +// returns the data of the node +Node.prototype.getData = function(){ + console.log(this.data); +}; + +// returns the next node, or null if no next node +Node.prototype.getNext = function(){ + if (this.next === null){ + return null; + } else { + console.log(this.next); + }; +}; + +// changes the reference to the next node and returns the original node +Node.prototype.setNext = function(element){ + this.next = element; + return this; +}; + +// const head = new Node(0, null); +const nodeA = new Node("apple", null); +const nodeB = new Node("banana", null); + +nodeA.getData(); +nodeA.setNext(nodeB); +nodeA.next = nodeB; +nodeA.getNext(); +// nodeB.next.getData(); +// NodeA.data.getData(); From 7fb584ce04aed2972370d485472081542a988e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Tue, 16 May 2017 01:31:03 -0700 Subject: [PATCH 07/38] add node test --- spec/nodeTest.js | 43 ++++++++++++++++++++++++++++++++++++++ src/node.js | 54 +++++++++++++++++++++--------------------------- 2 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 spec/nodeTest.js diff --git a/spec/nodeTest.js b/spec/nodeTest.js new file mode 100644 index 0000000..4fe610d --- /dev/null +++ b/spec/nodeTest.js @@ -0,0 +1,43 @@ + +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Node from '../src/node' + +chai.use(chaiChange) + +describe('Node', () => { + 'use strict' + const nodeA = new Node( {data: 'apple'} ) + const nodeB = new Node( {data: 'banana'} ) + + it('is a function', () => { + expect(Node).to.be.a('function') + }) + + context('getData()', () => { + it('gets the data from the node.', () => { + expect( nodeA.getData() ).to.equal('apple') + }) + }) + + context('setNext()', () => { + it('points the reference to the next node.', () => { + expect( () => nodeA.setNext(nodeB) ).to.alter( () => nodeA.data.next, { from: undefined, to: nodeB } ) + }) + + it('returns the original.', () => { + expect( nodeA.setNext(nodeB) ).to.equal(nodeA) + }) + }) + + context('getNext()', () => { + it('returns the next node', () => { + nodeA.setNext(nodeB) + expect( nodeA.getNext() ).to.equal(nodeB) + }) + + it('returns null if no next node.', () => { + expect( nodeB.getNext() ).to.equal(null) + }) + }) +}) diff --git a/src/node.js b/src/node.js index 76e2d7b..3ef7bd6 100644 --- a/src/node.js +++ b/src/node.js @@ -1,36 +1,28 @@ -// Node -- A very basic data structure that can contain some value and a reference to another node. -function Node(data, next){ - this.data = data; - this.next = next; -}; +'use strict' -// returns the data of the node -Node.prototype.getData = function(){ - console.log(this.data); -}; +// A very basic data structure that can contain some value and a reference to another node. +export default class Node { + constructor(data) { + this.data = data + this.next = undefined + } -// returns the next node, or null if no next node -Node.prototype.getNext = function(){ - if (this.next === null){ - return null; - } else { - console.log(this.next); - }; -}; +// returns the data ("apple") of the node + getData() { + return this.data.data + } // changes the reference to the next node and returns the original node -Node.prototype.setNext = function(element){ - this.next = element; - return this; -}; + setNext(element) { + this.data.next = element + return this + } -// const head = new Node(0, null); -const nodeA = new Node("apple", null); -const nodeB = new Node("banana", null); - -nodeA.getData(); -nodeA.setNext(nodeB); -nodeA.next = nodeB; -nodeA.getNext(); -// nodeB.next.getData(); -// NodeA.data.getData(); + // returns the next node, or null if no next node + getNext() { + if (this.data.next) { + return this.data.next + } + return null + } +} From e680b6a26a1dc2c329151ad2e11591410cfafb41 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 09:45:07 -0700 Subject: [PATCH 08/38] Added tests for getData and made test format more compact. --- spec/priority_node.js | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/spec/priority_node.js b/spec/priority_node.js index 74ed6d2..7ea2e6b 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -6,31 +6,43 @@ chai.use(chaiChange) describe('PriorityNode', () => { 'use strict' - it('is a function', () => { expect(PriorityNode).to.be.a('function') }) + const levelZero = new PriorityNode({data: "level0", priority: 0}) + const level0 = new PriorityNode({data: 0, priority: 0}) + const levelArrayNum = new PriorityNode({data: [1, 2], priority: 0}) + const levelArrayString = new PriorityNode({data: ["a", "b"], priority: 0}) + const levelObj = new PriorityNode({data: {"a": 1, "b": 2}, priority: 0}) + context('getData()', () => { - it('returns the correct type, if string', () => { - const levelZero = new PriorityNode({data: "level0", priority: 0}) - const data = levelZero.getData() - expect(data).to.be.a('string') + it('returns the correct type, if a string', () => { + expect(levelZero.getData()).to.be.a('string') }) it('returns the correct value, if a string', () => { - const levelZero = new PriorityNode({data: "level0", priority: 0}) - const data = levelZero.getData() - expect(data).to.be.equal('level0') + expect(levelZero.getData()).to.be.equal('level0') }) - it('returns the correct type, if number', () => { - const levelZero = new PriorityNode({data: 0, priority: 0}) - const data = levelZero.getData() - expect(data).to.be.a('number') + it('returns the correct type, if a number', () => { + expect(level0.getData()).to.be.a('number') }) it('returns the correct value, if a number', () => { - const levelZero = new PriorityNode({data: 0, priority: 0}) - const data = levelZero.getData() - expect(data).to.be.equal(0) + expect(level0.getData()).to.be.equal(0) + }) + it('returns the correct type, if an array', () => { + expect(Array.isArray(levelArrayNum.getData())).to.be.true + }) + it('returns the correct value, if an array', () => { + expect(levelArrayString.getData()).to.be.deep.equal(["a", "b"]) + }) + it('returns the correct type, if an object', () => { + expect(levelObj.getData()).to.be.an('object') + }) + it('returns the correct value, if an object', () => { + expect(levelObj.getData()).to.be.deep.equal({"a": 1, "b": 2}) + }) + it('returns an object with a retrievable property, if an object', () => { + expect(levelObj.getData().a).to.be.equal(1) }) }) }) From ade14d2b2855ed4bf38aeded2a75b1ad0bf58c03 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 11:23:01 -0700 Subject: [PATCH 09/38] Added checks in constructor for invalid and incomplete argument and added tests for those. --- spec/priority_node.js | 23 ++++++++++++++++++----- src/priority_node.js | 15 ++++++++++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/spec/priority_node.js b/spec/priority_node.js index 7ea2e6b..65337d5 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -6,15 +6,19 @@ chai.use(chaiChange) describe('PriorityNode', () => { 'use strict' + it('is a function', () => { expect(PriorityNode).to.be.a('function') }) - const levelZero = new PriorityNode({data: "level0", priority: 0}) + const levelZero = new PriorityNode({data: 'level0', priority: 0}) const level0 = new PriorityNode({data: 0, priority: 0}) const levelArrayNum = new PriorityNode({data: [1, 2], priority: 0}) - const levelArrayString = new PriorityNode({data: ["a", "b"], priority: 0}) - const levelObj = new PriorityNode({data: {"a": 1, "b": 2}, priority: 0}) + const levelArrayString = new PriorityNode({data: ['a', 'b'], priority: 0}) + const levelObj = new PriorityNode({data: {'a': 1, 'b': 2}, priority: 0}) + const priUnd = new PriorityNode({data: 'level0'}) + const levelUnd = new PriorityNode({priority: 0}) + const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) context('getData()', () => { it('returns the correct type, if a string', () => { @@ -33,16 +37,25 @@ describe('PriorityNode', () => { expect(Array.isArray(levelArrayNum.getData())).to.be.true }) it('returns the correct value, if an array', () => { - expect(levelArrayString.getData()).to.be.deep.equal(["a", "b"]) + expect(levelArrayString.getData()).to.be.deep.equal(['a', 'b']) }) it('returns the correct type, if an object', () => { expect(levelObj.getData()).to.be.an('object') }) it('returns the correct value, if an object', () => { - expect(levelObj.getData()).to.be.deep.equal({"a": 1, "b": 2}) + expect(levelObj.getData()).to.be.deep.equal({'a': 1, 'b': 2}) }) it('returns an object with a retrievable property, if an object', () => { expect(levelObj.getData().a).to.be.equal(1) }) + it('returns the correct value, if priority is unspecified', () => { + expect(priUnd.getData()).to.be.equal('level0') + }) + it('returns undefined, if undefined', () => { + expect(levelUnd.getData()).to.be.undefined + }) + it('returns undefined, if priority is not a number', () => { + expect(levZPriZ.getData()).to.be.undefined + }) }) }) diff --git a/src/priority_node.js b/src/priority_node.js index 4bf3de5..cf11e8a 100644 --- a/src/priority_node.js +++ b/src/priority_node.js @@ -6,9 +6,18 @@ */ export default class PriorityNode { constructor(nodeProps) { - this.data = nodeProps.data; - this.priority = nodeProps.priorty; - this.next = nodeProps.next; + // If the argument is valid: + if ( + nodeProps.data !== undefined + && ( + nodeProps.priority === undefined + || typeof(nodeProps.priority) === 'number' + ) + ) { + this.data = nodeProps.data; + this.priority = nodeProps.priority || 0; + this.next = nodeProps.next; + } } // Returns the node’s data. getData() { From 382ec8ae1966d6cd05d090db8097f31d97c8ab95 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 11:58:44 -0700 Subject: [PATCH 10/38] Added check and tests for next property of constructor argument. Added tests for getPriority method. --- spec/priority_node.js | 38 +++++++++++++++++++++++++++++++++++++- src/priority_node.js | 4 ++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/spec/priority_node.js b/spec/priority_node.js index 65337d5..199eb98 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -19,6 +19,8 @@ describe('PriorityNode', () => { const priUnd = new PriorityNode({data: 'level0'}) const levelUnd = new PriorityNode({priority: 0}) const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) + const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) + const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) context('getData()', () => { it('returns the correct type, if a string', () => { @@ -51,11 +53,45 @@ describe('PriorityNode', () => { it('returns the correct value, if priority is unspecified', () => { expect(priUnd.getData()).to.be.equal('level0') }) - it('returns undefined, if undefined', () => { + it('returns the correct value, if priority is unspecified', () => { + expect(priUnd.getData()).to.be.equal('level0') + }) + it('returns the correct value, if next node is specified', () => { + expect(next00.getData()).to.be.equal(-1) + }) + it('returns undefined, if unspecified', () => { expect(levelUnd.getData()).to.be.undefined }) it('returns undefined, if priority is not a number', () => { expect(levZPriZ.getData()).to.be.undefined }) + it('returns undefined, if next is not a PriorityNode', () => { + expect(next0Num.getData()).to.be.undefined + }) }) + + context('getPriority()', () => { + it('returns the correct type', () => { + expect(level0.getPriority()).to.be.a('number') + }) + it('returns the correct value', () => { + expect(level0.getPriority()).to.be.equal(0) + }) + it('returns the correct value, if next node is specified', () => { + expect(next00.getPriority()).to.be.equal(0) + }) + it('returns the default value, if unspecified', () => { + expect(priUnd.getPriority()).to.be.equal(0) + }) + it('returns undefined, if data unspecified', () => { + expect(levelUnd.getPriority()).to.be.undefined + }) + it('returns undefined, if not a number', () => { + expect(levZPriZ.getPriority()).to.be.undefined + }) + it('returns undefined, if next is not a PriorityNode', () => { + expect(next0Num.getPriority()).to.be.undefined + }) + }) + }) diff --git a/src/priority_node.js b/src/priority_node.js index cf11e8a..3db57a6 100644 --- a/src/priority_node.js +++ b/src/priority_node.js @@ -13,6 +13,10 @@ export default class PriorityNode { nodeProps.priority === undefined || typeof(nodeProps.priority) === 'number' ) + && ( + nodeProps.next === undefined + || nodeProps.next instanceof PriorityNode + ) ) { this.data = nodeProps.data; this.priority = nodeProps.priority || 0; From efe25b7662176beea916ab56ea1e94de1eb835ac Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 14:00:04 -0700 Subject: [PATCH 11/38] Added tests for getNext. --- spec/priority_node.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/spec/priority_node.js b/spec/priority_node.js index 199eb98..4bb963a 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -94,4 +94,31 @@ describe('PriorityNode', () => { }) }) + context('getNext()', () => { + it('returns the correct type, if specified', () => { + expect(next00.getNext() instanceof PriorityNode).to.be.true + }) + it('returns the correct value, if specified', () => { + expect(next00.getNext()).to.be.equal(level0) + }) + it( + 'returns a PriorityNode with a retrievable property, if specified', + () => { + expect(next00.getNext().getData()).to.be.equal(0) + } + ) + it('returns null, if unspecified', () => { + expect(level0.getNext()).to.be.null + }) + it('returns null, if specified but not a PriorityNode', () => { + expect(next0Num.getNext()).to.be.null + }) + it('returns null, if data is unspecified', () => { + expect(levelUnd.getNext()).to.be.null + }) + it('returns null, if priority is not a number', () => { + expect(levZPriZ.getNext()).to.be.null + }) + }) + }) From b76e83858426d45b6770631a9b15b1ff87514aff Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 15:08:16 -0700 Subject: [PATCH 12/38] Changed syntax of instanceof invocations. Added setNext tests. --- spec/priority_node.js | 26 ++++++++++++++++++++++++++ src/priority_node.js | 17 ++++++++++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/spec/priority_node.js b/spec/priority_node.js index 4bb963a..c289379 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -120,5 +120,31 @@ describe('PriorityNode', () => { expect(levZPriZ.getNext()).to.be.null }) }) + context('setNext()', () => { + it('returns a PriorityNode', () => { + expect(level0.setNext(levelZero) instanceof PriorityNode).to.be.true + }) + it('returns the correct PriorityNode', () => { + expect(level0.setNext(levelZero)).to.be.deep.equal(level0) + }) + it( + 'returns the PriorityNode with a retrievable priority property', + () => { + expect(level0.setNext(levelZero).getPriority()).to.be.equal(0) + } + ) + it( + 'returns the PriorityNode with a retrievable new next property', + () => { + expect(level0.setNext(levelZero).getNext()).to.be.deep.equal(levelZero) + } + ) + it( + 'fails to change next (from last valid value), if newNext is invalid', + () => { + expect(level0.setNext("next00").getNext()).to.be.deep.equal(levelZero) + } + ) + }) }) diff --git a/src/priority_node.js b/src/priority_node.js index 3db57a6..a7fc004 100644 --- a/src/priority_node.js +++ b/src/priority_node.js @@ -11,7 +11,7 @@ export default class PriorityNode { nodeProps.data !== undefined && ( nodeProps.priority === undefined - || typeof(nodeProps.priority) === 'number' + || typeof nodeProps.priority === 'number' ) && ( nodeProps.next === undefined @@ -35,15 +35,18 @@ export default class PriorityNode { getNext() { return this.next || null; } - // Changes the node’s priority and returns the post-change node. + // Changes the node’s priority and returns the node. setPriority(newPriority) { - this.priority = newPriority; + if (typeof newPriority === 'number') { + this.priority = newPriority; + } return this; } - // Changes the next node and returns the pre-change node. + // Changes the next node, if specified, and returns this node. setNext(newNext) { - const origThis = this; - this.next = newNext; - return origThis; + if (newNext instanceof PriorityNode) { + this.next = newNext; + } + return this; } } From 74997db391925681c1911e9badaed30b97ecf673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Tue, 16 May 2017 15:49:15 -0700 Subject: [PATCH 13/38] add linkedlist class and test --- spec/linkedListTest.js | 113 +++++++++++++++++++++++++++++++++++++++++ spec/nodeTest.js | 10 ++-- src/linkedList.js | 92 +++++++++++++++++++++++++++++++++ src/node.js | 20 ++++---- 4 files changed, 220 insertions(+), 15 deletions(-) create mode 100644 spec/linkedListTest.js create mode 100644 src/linkedList.js diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js new file mode 100644 index 0000000..0211bd6 --- /dev/null +++ b/spec/linkedListTest.js @@ -0,0 +1,113 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Node from '../src/node' +import LinkedList from '../src/linkedList' + +chai.use(chaiChange) + +describe('LinkedList', () => { + 'use strict' + const linkedList = new LinkedList() + + + it('is a function', () => { + expect(LinkedList).to.be.a('function') + }) + + context('insert()', () => { + const node = new Node( {data: 'firstNode'}) + it('inserts a node (with the provided data) to the tail of the list', () => { + expect( linkedList.insert(node) ).data.to.equal('firstNode') + }) + }) + + context('getHeadNode()', () => { + it('returns the first node in the list', () => { + expect( linkedList.getHeadNode() ).to.equal('firstNode') + }) + }) + + context('getTailNode()', () => { + it('returns the last node in the list', () => { + expect( linkedList.getTailNode() ).to.equal(nodeB) + }) + }) + + context('contains()', () => { + const node = new Node( {data: 'firstNode'}) + it('determines whether or not the list contains the provided data', () => { + expect( linkedList.contains() ).to.contain('value') + }) + }) + + context('insert()', () => { + const node = new Node( {data: 'firstNode'}) + it('inserts a node (with the provided data) to the tail of the list', () => { + expect( linkedList.getTailNode() ).to.equal('') + }) + }) + + context('find()', () => { + const node = new Node( {data: 'firstNode'}) + it('returns the first node containing the provided data, or -1 if not found', () => { + expect( linkedList.insert() ).to.equal('') + }) + }) + + context('insertFirst()', () => { + const node = new Node( {data: 'firstNode'}) + it('inserts a node (with the provided data) to the head of the list', () => { + expect( linkedList.getHeadNode() ).to.equal('') + }) + }) + + context('insertBefore()', () => { + const node = new Node( {data: 'firstNode'}) + it('inserts a node (with data "apples") before the first node containing "bananas"', () => { + expect(linkedList.insertBefore() ).to.equal('') + }) + }) + + context('insertAfter()', () => { + const node = new Node( {data: 'firstNode'}) + it('inserts a node (with data "bananas") after the first node containing "apples"', () => { + expect( linkedList.insertAfter() ).to.equal('') + }) + }) + + context('remove()', () => { + const node = new Node( {data: 'firstNode'}) + it('removes the tail node from the list', () => { + expect( linkedList.remove() ).to.equal('') + }) + }) + + context('removeFirst()', () => { + const node = new Node( {data: 'firstNode'}) + it('removes the head node from the list', () => { + expect( linkedList.removeFirst() ).to.equal('') + }) + }) + + context('isEmpty()', () => { + const node = new Node( {data: 'firstNode'}) + it('returns the first node in the list', () => { + expect( nodeA.isEmpty() ).to.equal('') + }) + }) + + context('size()', () => { + const node = new Node( {data: 'firstNode'}) + it('returns the size of the list (number of nodes)', () => { + expect( nodeA.size() ).to.equal('') + }) + }) + + context('clear()', () => { + const node = new Node( {data: 'firstNode'}) + it('clears the list of all nodes/data', () => { + expect( nodeA.clear() ).to.equal('') + }) + }) + +}) diff --git a/spec/nodeTest.js b/spec/nodeTest.js index 4fe610d..96f42a3 100644 --- a/spec/nodeTest.js +++ b/spec/nodeTest.js @@ -7,13 +7,14 @@ chai.use(chaiChange) describe('Node', () => { 'use strict' - const nodeA = new Node( {data: 'apple'} ) - const nodeB = new Node( {data: 'banana'} ) it('is a function', () => { expect(Node).to.be.a('function') }) + const nodeA = new Node( {data: 'apple'} ) + const nodeB = new Node( {data: 'banana'} ) + context('getData()', () => { it('gets the data from the node.', () => { expect( nodeA.getData() ).to.equal('apple') @@ -21,10 +22,9 @@ describe('Node', () => { }) context('setNext()', () => { - it('points the reference to the next node.', () => { - expect( () => nodeA.setNext(nodeB) ).to.alter( () => nodeA.data.next, { from: undefined, to: nodeB } ) + it('points the reference to the next node.', () => { + expect( () => nodeA.setNext(nodeB) ).to.alter( () => nodeA.next, { from: null, to: nodeB } ) }) - it('returns the original.', () => { expect( nodeA.setNext(nodeB) ).to.equal(nodeA) }) diff --git a/src/linkedList.js b/src/linkedList.js new file mode 100644 index 0000000..83d1b47 --- /dev/null +++ b/src/linkedList.js @@ -0,0 +1,92 @@ +import Node from '../src/node' + +'use strict' + +// A list of nodes that link to each other, like a daisy-chain. +export default class LinkedList { + constructor() { + this.head = null + this.tail = null + this.length = 0 + } + + + // Returns the first node in the list + getHeadNode(){ + return this.head + } + + // Returns the last node in the list + getTailNode(){ + return this.tail + } + + // Returns the size of the list (number of nodes) + size(){ + return this.length + } + + // Inserts a node (with the provided data) to the tail of the list + insert(nodeData){ + let node = new Node({data: 'nodeData'}) + if (this.head === null){ + this.head = node + } else { + let currentNode = this.head + while (currentNode.next){ + currentNode = currentNode.next + } + currentNode.next = node + } + + this.length++ + return node + } + + // Determines whether or not the list contains the provided data + contains(data){ + + } + + // Returns the first node containing the provided data, or -1 if not found + find(data){ + + } + + + + // Inserts a node (with the provided data) to the head of the list + insertFirst(data){ + + } + + // Inserts a node (with data "apples") before the first node containing "bananas" + insertBefore(data, index){ + + } + + // Inserts a node (with data "bananas") after the first node containing "apples" + insertAfter(data, inex){ + + } + + // Removes the tail node from the list + remove(){ + + } + + // Removes the head node from the list + removeFirst(){ + + } + + // Determines if the list is empty or not + isEmpty(){ + + } + + // Clears the list of all nodes/data + clear(){ + + } +} diff --git a/src/node.js b/src/node.js index 3ef7bd6..76c87df 100644 --- a/src/node.js +++ b/src/node.js @@ -2,26 +2,26 @@ // A very basic data structure that can contain some value and a reference to another node. export default class Node { - constructor(data) { - this.data = data - this.next = undefined + constructor(nodeProps) { + this.data = nodeProps.data + this.next = null } -// returns the data ("apple") of the node + // returns the data ("apple") of the node getData() { - return this.data.data + return this.data } -// changes the reference to the next node and returns the original node + // changes the reference to the next node and returns the original node setNext(element) { - this.data.next = element + this.next = element return this } - // returns the next node, or null if no next node + // returns the next node, or null if no next node getNext() { - if (this.data.next) { - return this.data.next + if (this.next) { + return this.next } return null } From c0776319cfc167b6c5859fffd62c33662a4dd315 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 15:51:59 -0700 Subject: [PATCH 14/38] Reorganized tests to create class instances for any context inside it. --- spec/priority_node.js | 63 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/spec/priority_node.js b/spec/priority_node.js index c289379..d27c57b 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -11,18 +11,17 @@ describe('PriorityNode', () => { expect(PriorityNode).to.be.a('function') }) - const levelZero = new PriorityNode({data: 'level0', priority: 0}) - const level0 = new PriorityNode({data: 0, priority: 0}) - const levelArrayNum = new PriorityNode({data: [1, 2], priority: 0}) - const levelArrayString = new PriorityNode({data: ['a', 'b'], priority: 0}) - const levelObj = new PriorityNode({data: {'a': 1, 'b': 2}, priority: 0}) - const priUnd = new PriorityNode({data: 'level0'}) - const levelUnd = new PriorityNode({priority: 0}) - const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) - const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) - const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) - context('getData()', () => { + const levelZero = new PriorityNode({data: 'level0', priority: 0}) + const level0 = new PriorityNode({data: 0, priority: 0}) + const levelArrayNum = new PriorityNode({data: [1, 2], priority: 0}) + const levelArrayString = new PriorityNode({data: ['a', 'b'], priority: 0}) + const levelObj = new PriorityNode({data: {'a': 1, 'b': 2}, priority: 0}) + const priUnd = new PriorityNode({data: 'level0'}) + const levelUnd = new PriorityNode({priority: 0}) + const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) + const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) + const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) it('returns the correct type, if a string', () => { expect(levelZero.getData()).to.be.a('string') }) @@ -71,6 +70,12 @@ describe('PriorityNode', () => { }) context('getPriority()', () => { + const level0 = new PriorityNode({data: 0, priority: 0}) + const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) + const priUnd = new PriorityNode({data: 'level0'}) + const levelUnd = new PriorityNode({priority: 0}) + const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) + const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) it('returns the correct type', () => { expect(level0.getPriority()).to.be.a('number') }) @@ -95,6 +100,11 @@ describe('PriorityNode', () => { }) context('getNext()', () => { + const level0 = new PriorityNode({data: 0, priority: 0}) + const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) + const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) + const levelUnd = new PriorityNode({priority: 0}) + const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) it('returns the correct type, if specified', () => { expect(next00.getNext() instanceof PriorityNode).to.be.true }) @@ -120,7 +130,36 @@ describe('PriorityNode', () => { expect(levZPriZ.getNext()).to.be.null }) }) + context('setPriority()', () => { + const level0 = new PriorityNode({data: 0, priority: 0}) + it('returns a PriorityNode', () => { + expect(level0.setPriority(2) instanceof PriorityNode).to.be.true + }) + it('returns the correct PriorityNode', () => { + expect(level0.setPriority(3)).to.be.deep.equal(level0) + }) + it( + 'returns the PriorityNode with a retrievable data property', + () => { + expect(level0.setPriority(4).getData()).to.be.equal(0) + } + ) + it( + 'returns the PriorityNode with a retrievable new priority property', + () => { + expect(level0.setPriority(5).getPriority()).to.be.equal(5) + } + ) + it( + 'fails to change priority (from last value), if newPriority is invalid', + () => { + expect(level0.setPriority("6").getPriority()).to.be.equal(5) + } + ) + }) context('setNext()', () => { + const level0 = new PriorityNode({data: 0, priority: 0}) + const levelZero = new PriorityNode({data: 'level0', priority: 0}) it('returns a PriorityNode', () => { expect(level0.setNext(levelZero) instanceof PriorityNode).to.be.true }) @@ -140,7 +179,7 @@ describe('PriorityNode', () => { } ) it( - 'fails to change next (from last valid value), if newNext is invalid', + 'fails to change next (from last value), if newNext is invalid', () => { expect(level0.setNext("next00").getNext()).to.be.deep.equal(levelZero) } From 5f63b73d5a46a7e8226039631aca046698c3bcf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Tue, 16 May 2017 17:06:55 -0700 Subject: [PATCH 15/38] update linledlist test --- spec/linkedListTest.js | 77 ++++++++++++++++++++++++------------------ src/linkedList.js | 4 +-- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 0211bd6..ce0d463 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -7,7 +7,7 @@ chai.use(chaiChange) describe('LinkedList', () => { 'use strict' - const linkedList = new LinkedList() + const list = new LinkedList() it('is a function', () => { @@ -15,98 +15,109 @@ describe('LinkedList', () => { }) context('insert()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'secondNode'} ) + const nodeC = new Node( {data: 'lastNode'} ) it('inserts a node (with the provided data) to the tail of the list', () => { - expect( linkedList.insert(node) ).data.to.equal('firstNode') + expect( list.insert() ).to.equal('firstNode') }) }) - context('getHeadNode()', () => { + context('getHead()', () => { + const nodeA = new Node( {data: 'firstNode'} ) it('returns the first node in the list', () => { - expect( linkedList.getHeadNode() ).to.equal('firstNode') + expect( list.getHead() ).to.equal(nodeA) }) }) - context('getTailNode()', () => { + context('getTail()', () => { + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'secondNode'} ) + const nodeC = new Node( {data: 'lastNode'} ) it('returns the last node in the list', () => { - expect( linkedList.getTailNode() ).to.equal(nodeB) + expect( list.getTail() ).to.equal(nodeC) }) }) context('contains()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'secondNode'} ) + const nodeC = new Node( {data: 'lastNode'} ) it('determines whether or not the list contains the provided data', () => { - expect( linkedList.contains() ).to.contain('value') - }) - }) - - context('insert()', () => { - const node = new Node( {data: 'firstNode'}) - it('inserts a node (with the provided data) to the tail of the list', () => { - expect( linkedList.getTailNode() ).to.equal('') + expect( list.contains('') ).to.contain('firstNode') }) }) context('find()', () => { - const node = new Node( {data: 'firstNode'}) + const node = new Node( {data: 'firstNode'} ) it('returns the first node containing the provided data, or -1 if not found', () => { - expect( linkedList.insert() ).to.equal('') + expect( list.find() ).to.equal('') }) }) context('insertFirst()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'secondNode'} ) + const nodeC = new Node( {data: 'lastNode'} ) it('inserts a node (with the provided data) to the head of the list', () => { - expect( linkedList.getHeadNode() ).to.equal('') + expect( list.insertFirst() ).to.equal('') }) }) context('insertBefore()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'bananas'} ) + const nodeB = new Node( {data: 'apples'} ) it('inserts a node (with data "apples") before the first node containing "bananas"', () => { - expect(linkedList.insertBefore() ).to.equal('') + expect( list.insertBefore() ).to.equal('') }) }) context('insertAfter()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'apple'} ) + const nodeB = new Node( {data: 'bananas'} ) it('inserts a node (with data "bananas") after the first node containing "apples"', () => { - expect( linkedList.insertAfter() ).to.equal('') + expect( list.insertAfter() ).to.equal('') }) }) context('remove()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'secondNode'} ) + const nodeC = new Node( {data: 'thirdNode'} ) it('removes the tail node from the list', () => { - expect( linkedList.remove() ).to.equal('') + expect( list.remove() ).to.equal(nodeC) }) }) context('removeFirst()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'secondNode'} ) + const nodeC = new Node( {data: 'thirdNode'} ) it('removes the head node from the list', () => { - expect( linkedList.removeFirst() ).to.equal('') + expect( list.removeFirst() ).to.equal(nodeA) }) }) context('isEmpty()', () => { - const node = new Node( {data: 'firstNode'}) + const node = new Node( {} ) it('returns the first node in the list', () => { - expect( nodeA.isEmpty() ).to.equal('') + expect( nodeA.isEmpty() ).to.equal(undefined) }) }) context('size()', () => { - const node = new Node( {data: 'firstNode'}) + const nodeA = new Node( {data: 'firstNode'} ) + const nodeB = new Node( {data: 'firstNode'} ) + const nodeC = new Node( {data: 'firstNode'} ) it('returns the size of the list (number of nodes)', () => { - expect( nodeA.size() ).to.equal('') + expect( nodeA.size() ).to.equal(this.size) }) }) context('clear()', () => { const node = new Node( {data: 'firstNode'}) it('clears the list of all nodes/data', () => { - expect( nodeA.clear() ).to.equal('') + expect( list.size ).to.equal(0) }) }) diff --git a/src/linkedList.js b/src/linkedList.js index 83d1b47..b2550b7 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -12,12 +12,12 @@ export default class LinkedList { // Returns the first node in the list - getHeadNode(){ + getHead(){ return this.head } // Returns the last node in the list - getTailNode(){ + getTail(){ return this.tail } From 193e7faeb0fab3328f65557d609fbd2889e75b0e Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Tue, 16 May 2017 22:40:38 -0700 Subject: [PATCH 16/38] Finished implementing, testing, and debugging priorityQueue class. --- spec/priority_queue.js | 72 ++++++++++++++++++++++++++++++++++++++++++ src/priority_queue.js | 50 +++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 spec/priority_queue.js create mode 100644 src/priority_queue.js diff --git a/spec/priority_queue.js b/spec/priority_queue.js new file mode 100644 index 0000000..94d1a41 --- /dev/null +++ b/spec/priority_queue.js @@ -0,0 +1,72 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import PriorityQueue from '../src/priority_queue' + +chai.use(chaiChange) + +describe('PriorityQueue', () => { + 'use strict' + + it('is a function', () => { + expect(PriorityQueue).to.be.a('function') + }) + + context('empty queue', () => { + const emptyQueue = new PriorityQueue() + it('front() returns null', () => { + expect(emptyQueue.front()).to.be.null + }) + it('back() returns null', () => { + expect(emptyQueue.back()).to.be.null + }) + it('isEmpty() returns true', () => { + expect(emptyQueue.isEmpty()).to.be.true + }) + it('length() returns 0', () => { + expect(emptyQueue.length()).to.be.equal(0) + }) + it('dequeue() returns null', () => { + expect(emptyQueue.dequeue()).to.be.null + }) + }) + + context('non-empty queue', () => { + const pQueue = new PriorityQueue() + pQueue.enqueue('bad', 10) + pQueue.enqueue('ok', 50) + pQueue.enqueue('good', 90) + it('the element front() returns has priority 90', () => { + expect(pQueue.front().getPriority()).to.be.equal(90) + }) + it('the element front() returns has data “good”', () => { + expect(pQueue.front().getData()).to.be.equal('good') + }) + it('the element back() returns has priority 10', () => { + expect(pQueue.back().getPriority()).to.be.equal(10) + }) + it('isEmpty() returns false', () => { + expect(pQueue.isEmpty()).to.be.false + }) + it('length() returns 3', () => { + expect(pQueue.length()).to.be.equal(3) + }) + it('the element dequeue() returns has priority 90', () => { + expect(pQueue.dequeue().getPriority()).to.be.equal(90) + }) + it('the length is 2 after 1 dequeuing', () => { + expect(pQueue.length()).to.be.equal(2) + }) + it('the highest priority is 50 after 1 dequeuing', () => { + expect(pQueue.front().getPriority()).to.be.equal(50) + }) + it('the length is 3 after a valid enqueuing', () => { + pQueue.enqueue('horrible', 0); + expect(pQueue.length()).to.be.equal(3) + }) + it('the length stays 3 after an invalid enqueuing', () => { + pQueue.enqueue('wonderful', '100'); + expect(pQueue.length()).to.be.equal(3) + }) + }) + +}) diff --git a/src/priority_queue.js b/src/priority_queue.js new file mode 100644 index 0000000..21fe40b --- /dev/null +++ b/src/priority_queue.js @@ -0,0 +1,50 @@ +'use strict'; +import PriorityNode from './priority_node'; + +/* + Class declaration for PriorityQueue and export statement making that + object the default export from this module. +*/ +export default class PriorityQueue { + constructor() { + this.queue = []; + } + // Returns the count of elements with priorities lower than specified. + lowerCount(priority) { + let lowerCount = 0; + while ( + lowerCount < this.queue.length + && this.queue[lowerCount].getPriority() < priority + ) { + lowerCount++; + } + return lowerCount; + } + // Adds a specified element to the queue. + enqueue(d, p) { + const newNode = new PriorityNode({data: d, priority: p}); + if (newNode.data !== undefined) { + this.queue.splice(this.lowerCount(p), 0, newNode); + } + } + // Returns the highest-priority node. + front() { + return this.queue[this.queue.length - 1] || null; + } + // Returns the lowest-priority node. + back() { + return this.queue[0] || null; + } + // Returns whether the queue is empty. + isEmpty() { + return this.queue.length === 0; + } + // Changes the next node, if specified, and returns this node. + length() { + return this.queue.length; + } + // Adds a specified element to the queue. + dequeue() { + return this.queue.pop() || null; + } +} From e2cc86263df023c291c104a79e9ec1e21720cf49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Tue, 16 May 2017 22:50:15 -0700 Subject: [PATCH 17/38] reset linked list tests --- spec/linkedListTest.js | 96 ------------------------------------------ src/linkedList.js | 63 --------------------------- 2 files changed, 159 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index ce0d463..cc4e1d7 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -23,102 +23,6 @@ describe('LinkedList', () => { }) }) - context('getHead()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - it('returns the first node in the list', () => { - expect( list.getHead() ).to.equal(nodeA) - }) - }) - context('getTail()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'secondNode'} ) - const nodeC = new Node( {data: 'lastNode'} ) - it('returns the last node in the list', () => { - expect( list.getTail() ).to.equal(nodeC) - }) - }) - - context('contains()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'secondNode'} ) - const nodeC = new Node( {data: 'lastNode'} ) - it('determines whether or not the list contains the provided data', () => { - expect( list.contains('') ).to.contain('firstNode') - }) - }) - - context('find()', () => { - const node = new Node( {data: 'firstNode'} ) - it('returns the first node containing the provided data, or -1 if not found', () => { - expect( list.find() ).to.equal('') - }) - }) - - context('insertFirst()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'secondNode'} ) - const nodeC = new Node( {data: 'lastNode'} ) - it('inserts a node (with the provided data) to the head of the list', () => { - expect( list.insertFirst() ).to.equal('') - }) - }) - - context('insertBefore()', () => { - const nodeA = new Node( {data: 'bananas'} ) - const nodeB = new Node( {data: 'apples'} ) - it('inserts a node (with data "apples") before the first node containing "bananas"', () => { - expect( list.insertBefore() ).to.equal('') - }) - }) - - context('insertAfter()', () => { - const nodeA = new Node( {data: 'apple'} ) - const nodeB = new Node( {data: 'bananas'} ) - it('inserts a node (with data "bananas") after the first node containing "apples"', () => { - expect( list.insertAfter() ).to.equal('') - }) - }) - - context('remove()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'secondNode'} ) - const nodeC = new Node( {data: 'thirdNode'} ) - it('removes the tail node from the list', () => { - expect( list.remove() ).to.equal(nodeC) - }) - }) - - context('removeFirst()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'secondNode'} ) - const nodeC = new Node( {data: 'thirdNode'} ) - it('removes the head node from the list', () => { - expect( list.removeFirst() ).to.equal(nodeA) - }) - }) - - context('isEmpty()', () => { - const node = new Node( {} ) - it('returns the first node in the list', () => { - expect( nodeA.isEmpty() ).to.equal(undefined) - }) - }) - - context('size()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'firstNode'} ) - const nodeC = new Node( {data: 'firstNode'} ) - it('returns the size of the list (number of nodes)', () => { - expect( nodeA.size() ).to.equal(this.size) - }) - }) - - context('clear()', () => { - const node = new Node( {data: 'firstNode'}) - it('clears the list of all nodes/data', () => { - expect( list.size ).to.equal(0) - }) - }) }) diff --git a/src/linkedList.js b/src/linkedList.js index b2550b7..a407883 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -10,23 +10,6 @@ export default class LinkedList { this.length = 0 } - - // Returns the first node in the list - getHead(){ - return this.head - } - - // Returns the last node in the list - getTail(){ - return this.tail - } - - // Returns the size of the list (number of nodes) - size(){ - return this.length - } - - // Inserts a node (with the provided data) to the tail of the list insert(nodeData){ let node = new Node({data: 'nodeData'}) if (this.head === null){ @@ -43,50 +26,4 @@ export default class LinkedList { return node } - // Determines whether or not the list contains the provided data - contains(data){ - - } - - // Returns the first node containing the provided data, or -1 if not found - find(data){ - - } - - - - // Inserts a node (with the provided data) to the head of the list - insertFirst(data){ - - } - - // Inserts a node (with data "apples") before the first node containing "bananas" - insertBefore(data, index){ - - } - - // Inserts a node (with data "bananas") after the first node containing "apples" - insertAfter(data, inex){ - - } - - // Removes the tail node from the list - remove(){ - - } - - // Removes the head node from the list - removeFirst(){ - - } - - // Determines if the list is empty or not - isEmpty(){ - - } - - // Clears the list of all nodes/data - clear(){ - - } } From 79ff910d79d36e8b925d65d99324b242ebaff162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 06:55:56 -0700 Subject: [PATCH 18/38] pass insert and getHead tests --- spec/linkedListTest.js | 24 +++++++++++++++++------- spec/nodeTest.js | 15 ++++++++++----- src/linkedList.js | 30 ++++++++++++++++-------------- src/node.js | 4 ++-- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index cc4e1d7..e307237 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -8,21 +8,31 @@ chai.use(chaiChange) describe('LinkedList', () => { 'use strict' const list = new LinkedList() - + list.insert( 'apple') + list.insert ( 'banana' ) it('is a function', () => { - expect(LinkedList).to.be.a('function') + expect( LinkedList ).to.be.a( 'function' ) + }) + + context( 'getHeadNode', () => { + it( 'returns the first node in the list', () => { + expect ( list.getHeadNode().data ).to.equal( 'apple' ) + }) }) context('insert()', () => { - const nodeA = new Node( {data: 'firstNode'} ) - const nodeB = new Node( {data: 'secondNode'} ) - const nodeC = new Node( {data: 'lastNode'} ) - it('inserts a node (with the provided data) to the tail of the list', () => { - expect( list.insert() ).to.equal('firstNode') + it('inserts node to the tail', () => { + list.insert( 'papaya' ) + expect( list.tail.data ).to.equal( 'papaya') }) }) + + + + + }) diff --git a/spec/nodeTest.js b/spec/nodeTest.js index 96f42a3..8303431 100644 --- a/spec/nodeTest.js +++ b/spec/nodeTest.js @@ -12,17 +12,20 @@ describe('Node', () => { expect(Node).to.be.a('function') }) - const nodeA = new Node( {data: 'apple'} ) - const nodeB = new Node( {data: 'banana'} ) - context('getData()', () => { + const nodeA = new Node( {data: 'apple'} ) + const nodeB = new Node( {data: 'banana'} ) + const nodeC = new Node( {data: 'orange'} ) it('gets the data from the node.', () => { expect( nodeA.getData() ).to.equal('apple') }) }) context('setNext()', () => { - it('points the reference to the next node.', () => { + const nodeA = new Node( {data: 'apple'} ) + const nodeB = new Node( {data: 'banana'} ) + const nodeC = new Node( {data: 'orange'} ) + it('points the reference to the next node.', () => { expect( () => nodeA.setNext(nodeB) ).to.alter( () => nodeA.next, { from: null, to: nodeB } ) }) it('returns the original.', () => { @@ -31,11 +34,13 @@ describe('Node', () => { }) context('getNext()', () => { + const nodeA = new Node( {data: 'apple'} ) + const nodeB = new Node( {data: 'banana'} ) + const nodeC = new Node( {data: 'orange'} ) it('returns the next node', () => { nodeA.setNext(nodeB) expect( nodeA.getNext() ).to.equal(nodeB) }) - it('returns null if no next node.', () => { expect( nodeB.getNext() ).to.equal(null) }) diff --git a/src/linkedList.js b/src/linkedList.js index a407883..ba389fd 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -4,26 +4,28 @@ import Node from '../src/node' // A list of nodes that link to each other, like a daisy-chain. export default class LinkedList { - constructor() { + constructor( listData ) { this.head = null this.tail = null this.length = 0 } - insert(nodeData){ - let node = new Node({data: 'nodeData'}) - if (this.head === null){ - this.head = node - } else { - let currentNode = this.head - while (currentNode.next){ - currentNode = currentNode.next - } - currentNode.next = node - } + getHeadNode(){ + return this.head + } + + insert( nodeData ){ + let newNode = new Node( nodeData ) + let currentNode = this.head - this.length++ - return node + if ( !currentNode ) { + this.head = newNode + this.tail = newNode + } else { + this.tail.next = newNode + this.tail = newNode + } + this.length++ } } diff --git a/src/node.js b/src/node.js index 76c87df..3fd7f13 100644 --- a/src/node.js +++ b/src/node.js @@ -2,8 +2,8 @@ // A very basic data structure that can contain some value and a reference to another node. export default class Node { - constructor(nodeProps) { - this.data = nodeProps.data + constructor( data ) { + this.data = data this.next = null } From b19505f1229aefd5952ea83531649cbb33c426ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 07:05:09 -0700 Subject: [PATCH 19/38] pass insert and getHead tests --- spec/linkedListTest.js | 6 ++++++ src/linkedList.js | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index e307237..74dfacb 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -21,6 +21,12 @@ describe('LinkedList', () => { }) }) + context( 'getTailNode', () => { + it( 'returns the lastnode in the list', () => { + expect( list.getTailNode().data ).to.equal( 'banana') + }) + }) + context('insert()', () => { it('inserts node to the tail', () => { list.insert( 'papaya' ) diff --git a/src/linkedList.js b/src/linkedList.js index ba389fd..9e2cecf 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -14,6 +14,10 @@ export default class LinkedList { return this.head } + getTailNode() { + return this.tail + } + insert( nodeData ){ let newNode = new Node( nodeData ) let currentNode = this.head From 77ab88c581b46401d8d81ada43242b44cc22c1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 07:24:57 -0700 Subject: [PATCH 20/38] pass contains test --- spec/linkedListTest.js | 10 +++++++--- src/linkedList.js | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 74dfacb..5aa2a1c 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -27,14 +27,18 @@ describe('LinkedList', () => { }) }) - context('insert()', () => { - it('inserts node to the tail', () => { + context( 'insert()', () => { + it( 'inserts node to the tail', () => { list.insert( 'papaya' ) expect( list.tail.data ).to.equal( 'papaya') }) }) - + context( 'contains()', () => { + it( 'determines wether ir not the list contains the provided data', () => { + expect( list.contains( 'cherry' ) ).to.equal( false ) + }) + }) diff --git a/src/linkedList.js b/src/linkedList.js index 9e2cecf..9eaa2da 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -32,4 +32,18 @@ export default class LinkedList { this.length++ } + contains( fruit ){ + let currentNode = this.head + + while( currentNode ) { + if ( currentNode.data === fruit) { + return true + } + if ( currentNode = this.tail ) { + return false + } else { + currentNode = currentNode.next + } + } + } } From 481143100f2c2bf9d65bb53d9fbc179e1fee2f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 09:38:10 -0700 Subject: [PATCH 21/38] update linkedlist test --- spec/linkedListTest.js | 11 +++++++++-- src/linkedList.js | 43 +++++++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 5aa2a1c..7277554 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -35,12 +35,19 @@ describe('LinkedList', () => { }) context( 'contains()', () => { - it( 'determines wether ir not the list contains the provided data', () => { + it( 'determines whether or not the list contains the provided data', () => { expect( list.contains( 'cherry' ) ).to.equal( false ) }) }) - + context( 'find()', () => { + it( 'returns the first node containind the prodived data', () => { + expect( list.find( 'banana' ) ).to.equal( 'banana' ) + }) + it( 'returns - 1 if not found', () => { + expect( list.find( 'cherry' ) ).to.equal(-1) + }) + }) diff --git a/src/linkedList.js b/src/linkedList.js index 9eaa2da..2d7f56e 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -18,6 +18,36 @@ export default class LinkedList { return this.tail } + contains( fruit ){ + let currentNode = this.head + + while( currentNode ) { + if ( currentNode.data === fruit) { + return true + } + if ( currentNode = this.tail ) { + return false + } else { + currentNode = currentNode.next + } + } + } + + find( fruit ){ + let currentNode = this.head + + while ( currentNode ) { + if ( currentNode.dada == fruit ){ + return currentNode.data + } + if ( currentNode === this.tail.data ) { + return -1 + } else { + currentNode = currentNode.next + } + } + } + insert( nodeData ){ let newNode = new Node( nodeData ) let currentNode = this.head @@ -32,18 +62,5 @@ export default class LinkedList { this.length++ } - contains( fruit ){ - let currentNode = this.head - while( currentNode ) { - if ( currentNode.data === fruit) { - return true - } - if ( currentNode = this.tail ) { - return false - } else { - currentNode = currentNode.next - } - } - } } From db9e1341ac1e74d83c49d81c951efde53adaf7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 11:23:49 -0700 Subject: [PATCH 22/38] pass find text --- spec/linkedListTest.js | 14 ++++++++------ spec/nodeTest.js | 4 +--- src/linkedList.js | 26 ++++++++++++++------------ src/node.js | 8 ++++---- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 7277554..6a07e01 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -8,8 +8,9 @@ chai.use(chaiChange) describe('LinkedList', () => { 'use strict' const list = new LinkedList() - list.insert( 'apple') - list.insert ( 'banana' ) + list.insert( {data: 'apple'} ) + list.insert( {data: 'banana'} ) + list.insert( {data: 'orange'} ) it('is a function', () => { expect( LinkedList ).to.be.a( 'function' ) @@ -17,19 +18,20 @@ describe('LinkedList', () => { context( 'getHeadNode', () => { it( 'returns the first node in the list', () => { + console.log(list) expect ( list.getHeadNode().data ).to.equal( 'apple' ) }) }) context( 'getTailNode', () => { it( 'returns the lastnode in the list', () => { - expect( list.getTailNode().data ).to.equal( 'banana') + expect( list.getTailNode().data ).to.equal( 'orange') }) }) context( 'insert()', () => { it( 'inserts node to the tail', () => { - list.insert( 'papaya' ) + list.insert( { data: 'papaya' } ) expect( list.tail.data ).to.equal( 'papaya') }) }) @@ -41,10 +43,10 @@ describe('LinkedList', () => { }) context( 'find()', () => { - it( 'returns the first node containind the prodived data', () => { + it( 'returns the first node contains the prodived data', () => { expect( list.find( 'banana' ) ).to.equal( 'banana' ) }) - it( 'returns - 1 if not found', () => { + it( 'returns -1 if not found', () => { expect( list.find( 'cherry' ) ).to.equal(-1) }) }) diff --git a/spec/nodeTest.js b/spec/nodeTest.js index 8303431..d39923b 100644 --- a/spec/nodeTest.js +++ b/spec/nodeTest.js @@ -13,9 +13,7 @@ describe('Node', () => { }) context('getData()', () => { - const nodeA = new Node( {data: 'apple'} ) - const nodeB = new Node( {data: 'banana'} ) - const nodeC = new Node( {data: 'orange'} ) + const nodeA = new Node( {data: 'apple'}) it('gets the data from the node.', () => { expect( nodeA.getData() ).to.equal('apple') }) diff --git a/src/linkedList.js b/src/linkedList.js index 2d7f56e..8867688 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -4,7 +4,7 @@ import Node from '../src/node' // A list of nodes that link to each other, like a daisy-chain. export default class LinkedList { - constructor( listData ) { + constructor( data ) { this.head = null this.tail = null this.length = 0 @@ -36,23 +36,25 @@ export default class LinkedList { find( fruit ){ let currentNode = this.head - while ( currentNode ) { - if ( currentNode.dada == fruit ){ + while ( currentNode.next !== null ) { + if ( currentNode.data === fruit ){ return currentNode.data } - if ( currentNode === this.tail.data ) { - return -1 - } else { - currentNode = currentNode.next - } - } + currentNode = currentNode.next + } + + if ( fruit === this.tail.data ) { + return currentNode.data + } + return -1 } - insert( nodeData ){ - let newNode = new Node( nodeData ) + + insert( fruit ){ + let newNode = new Node( fruit ) let currentNode = this.head - if ( !currentNode ) { + if ( !currentNode && this.length === 0 ) { this.head = newNode this.tail = newNode } else { diff --git a/src/node.js b/src/node.js index 3fd7f13..0edc003 100644 --- a/src/node.js +++ b/src/node.js @@ -2,8 +2,8 @@ // A very basic data structure that can contain some value and a reference to another node. export default class Node { - constructor( data ) { - this.data = data + constructor( nodeData ) { + this.data = nodeData.data this.next = null } @@ -13,14 +13,14 @@ export default class Node { } // changes the reference to the next node and returns the original node - setNext(element) { + setNext( element ) { this.next = element return this } // returns the next node, or null if no next node getNext() { - if (this.next) { + if ( this.next ) { return this.next } return null From 5d358333a74a4c6cf500e4bd24d970a10833425d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 13:39:58 -0700 Subject: [PATCH 23/38] pass insertFirst test --- spec/linkedListTest.js | 9 +++++++-- src/linkedList.js | 20 ++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 6a07e01..08d65b7 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -18,7 +18,6 @@ describe('LinkedList', () => { context( 'getHeadNode', () => { it( 'returns the first node in the list', () => { - console.log(list) expect ( list.getHeadNode().data ).to.equal( 'apple' ) }) }) @@ -44,13 +43,19 @@ describe('LinkedList', () => { context( 'find()', () => { it( 'returns the first node contains the prodived data', () => { - expect( list.find( 'banana' ) ).to.equal( 'banana' ) + expect( list.find( 'banana' ).getData() ).to.equal( 'banana' ) }) it( 'returns -1 if not found', () => { expect( list.find( 'cherry' ) ).to.equal(-1) }) }) + context( 'insertFirst()', () => { + it ( 'inserts a node at the head of the list', () => { + list.insertFirst( { data: 'guava' } ) + expect( list.head.data ).to.equal( 'guava') + }) + }) diff --git a/src/linkedList.js b/src/linkedList.js index 8867688..8772290 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -38,18 +38,13 @@ export default class LinkedList { while ( currentNode.next !== null ) { if ( currentNode.data === fruit ){ - return currentNode.data + return currentNode } currentNode = currentNode.next } - - if ( fruit === this.tail.data ) { - return currentNode.data - } return -1 } - insert( fruit ){ let newNode = new Node( fruit ) let currentNode = this.head @@ -64,5 +59,18 @@ export default class LinkedList { this.length++ } + insertFirst(fruit){ + let newNode = new Node( fruit ) + let currentNode = this.head + if ( !currentNode ) { + this.head = newNode + this.tail = newNode + } else { + newNode.next = this.head + this.head = newNode + } + currentNode = currentNode.next + this.length++ + } } From bf1c49272fe7797571e54e6d5fb83a00c443ef30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Wed, 17 May 2017 17:07:14 -0700 Subject: [PATCH 24/38] pass insertBefore test --- spec/linkedListTest.js | 16 ++++++++++++---- src/linkedList.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 08d65b7..b970f0b 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -5,7 +5,7 @@ import LinkedList from '../src/linkedList' chai.use(chaiChange) -describe('LinkedList', () => { +describe.only('LinkedList', () => { 'use strict' const list = new LinkedList() list.insert( {data: 'apple'} ) @@ -51,9 +51,17 @@ describe('LinkedList', () => { }) context( 'insertFirst()', () => { - it ( 'inserts a node at the head of the list', () => { - list.insertFirst( { data: 'guava' } ) - expect( list.head.data ).to.equal( 'guava') + it( 'inserts a node at the head of the list', () => { + list.insertFirst( { data: 'bananas' } ) + expect( list.head.data ).to.equal( 'bananas') + }) + }) + + context( 'insertBefore', () => { + it( 'inserts a node before a specified node', () => { + list.insertBefore( 'bananas', 'apples' ) + console.log(list) + expect( list.head.next.data ).to.equal( 'bananas' ) }) }) diff --git a/src/linkedList.js b/src/linkedList.js index 8772290..b2c01e8 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -73,4 +73,36 @@ export default class LinkedList { currentNode = currentNode.next this.length++ } + + insertBefore( target, data){ + let newNode = new Node( data ) + let currentNode = this.head + + if ( this.length == 1 ) { + newNode.next = this.head + this.head = newNode + } + + while ( currentNode ) { + if ( currentNode.data == target) { + newNode.next = currentNode + this.head = newNode + return + } + + if ( currentNode.next.data == target ) { + newNode.next = currentNode.next + currentNode.next = newNode + return + } + if ( currentNode == this.tail ){ + return 'non-existent node in this list.' + } + else { + currentNode = currentNode.next + } + + } + this.length++ + } } From abea694d370a476236c9cd8648fc8d25c4477810 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Wed, 17 May 2017 21:54:25 -0700 Subject: [PATCH 25/38] Changed mocha function syntax from => per mocha recommendation. Created, tested, and debugged double node and doubly linked list classes. --- .gitignore | 1 + spec/double_node.js | 138 +++++++++++++++++++++++++++++++++++++ spec/doubly_linked_list.js | 118 +++++++++++++++++++++++++++++++ spec/priority_node.js | 104 ++++++++++++++-------------- spec/priority_queue.js | 38 +++++----- src/double_node.js | 53 ++++++++++++++ src/doubly_linked_list.js | 137 ++++++++++++++++++++++++++++++++++++ src/node2.js | 36 ++++++++++ 8 files changed, 555 insertions(+), 70 deletions(-) create mode 100644 spec/double_node.js create mode 100644 spec/doubly_linked_list.js create mode 100644 src/double_node.js create mode 100644 src/doubly_linked_list.js create mode 100644 src/node2.js diff --git a/.gitignore b/.gitignore index 2752eb9..0cd47de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ .DS_Store +notes.txt diff --git a/spec/double_node.js b/spec/double_node.js new file mode 100644 index 0000000..26eabe3 --- /dev/null +++ b/spec/double_node.js @@ -0,0 +1,138 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import DoubleNode from '../src/double_node' + +chai.use(chaiChange) + +describe('DoubleNode', function() { + 'use strict' + + it('is a function', function() { + expect(DoubleNode).to.be.a('function') + }) + + context('getData()', function() { + const dsNode = new DoubleNode({data: 'string'}) + const dnNode = new DoubleNode({data: 0}) + const daNode = new DoubleNode({data: [1, 2]}) + const doNode = new DoubleNode({data: {'a': 1, 'b': 2}}) + const emptyNode = new DoubleNode() + const ngNode = new DoubleNode({data: 1, next: dsNode}) + const nbNode = new DoubleNode({data: 2, next: "dnNode"}) + const pgNode = new DoubleNode({data: 3, previous: dnNode}) + const pgbNode = new DoubleNode({data: 4, previous: emptyNode}) + it('returns the correct type, if a string', function() { + expect(dsNode.getData()).to.be.a('string') + }) + it('returns the correct value, if a string', function() { + expect(dsNode.getData()).to.be.equal('string') + }) + it('returns the correct type, if a number', function() { + expect(dnNode.getData()).to.be.a('number') + }) + it('returns the correct value, if a number', function() { + expect(dnNode.getData()).to.be.equal(0) + }) + it('returns the correct type, if an array', function() { + expect(Array.isArray(daNode.getData())).to.be.true + }) + it('returns the correct value, if an array', function() { + expect(daNode.getData()).to.be.deep.equal([1, 2]) + }) + it('returns the correct type, if an object', function() { + expect(doNode.getData()).to.be.an('object') + }) + it('returns the correct value, if an object', function() { + expect(doNode.getData()).to.be.deep.equal({'a': 1, 'b': 2}) + }) + it('returns an object with a retrievable property, if an object', function() { + expect(doNode.getData().a).to.be.equal(1) + }) + it('returns the correct value, if next is specified', function() { + expect(ngNode.getData()).to.be.equal(1) + }) + it('returns the correct value, if previous is specified', function() { + expect(pgNode.getData()).to.be.equal(3) + }) + it('returns the correct value, if previous is a bad DoubleNode', function() { + expect(pgbNode.getData()).to.be.equal(4) + }) + it('returns undefined, if unspecified', function() { + expect(emptyNode.getData()).to.be.undefined + }) + it('returns undefined, if next is not a DoubleNode', function() { + expect(nbNode.getData()).to.be.undefined + }) + }) + + context('getNext()', function() { + const nnNode = new DoubleNode({data: 'string'}) + const ngNode = new DoubleNode({data: 0, next: nnNode}) + const nbNode = new DoubleNode({data: 1, next: 0}) + const dxnbNode = new DoubleNode({next: ngNode}) + const ngbNode = new DoubleNode({data: 0, next: dxnbNode}) + const emptyNode = new DoubleNode() + const pgNode = new DoubleNode({data: 2, next: nnNode, previous: nnNode}) + const pgbNode = new DoubleNode({data: 3, next: ngNode, previous: nbNode}) + const pbNode = new DoubleNode({data: 4, next: ngNode, previous: "node"}) + it('returns the correct type, if specified', function() { + expect(ngNode.getNext() instanceof DoubleNode).to.be.true + }) + it('returns the correct value, if specified', function() { + expect(ngNode.getNext()).to.be.deep.equal(nnNode) + }) + it( + 'returns a DoubleNode with a retrievable property, if specified', + function() { + expect(ngNode.getNext().getData()).to.be.equal('string') + } + ) + it('returns null, if unspecified', function() { + expect(nnNode.getNext()).to.be.null + }) + it('returns null, if specified but not a DoubleNode', function() { + expect(nbNode.getNext()).to.be.null + }) + it('returns null, if specified but data is unspecified', function() { + expect(dxnbNode.getNext()).to.be.null + }) + }) + + context('setNext()', function() { + const nnNode = new DoubleNode({data: 0}) + const ngNode = new DoubleNode({data: 'string', next: nnNode}) + const nbNode = new DoubleNode({data: 1, next: "nonode"}) + const pbNode = new DoubleNode({data: 2, next: ngNode, previous: "bad"}) + it('returns a DoubleNode', function() { + expect(nnNode.setNext(ngNode) instanceof DoubleNode).to.be.true + }) + it('returns the correct DoubleNode', function() { + expect(nnNode.setNext(ngNode)).to.be.deep.equal(nnNode) + }) + it( + 'returns a DoubleNode with a retrievable data property', + function() { + expect(ngNode.setNext(nnNode).getData()).to.be.equal('string') + } + ) + it( + 'returns a DoubleNode with a retrievable good new next property', + function() { + expect(nnNode.setNext(ngNode).getNext()).to.be.deep.equal(ngNode) + } + ) + it( + 'returns a DoubleNode with a retrievable bad new next property', + function() { + expect(nnNode.setNext(nbNode).getNext()).to.be.deep.equal(nbNode) + } + ) + it( + 'fails to change next (from last value), if newNext is invalid', + function() { + expect(nnNode.setNext("badNode").getNext()).to.be.deep.equal(nbNode) + } + ) + }) + +}) diff --git a/spec/doubly_linked_list.js b/spec/doubly_linked_list.js new file mode 100644 index 0000000..9366f6e --- /dev/null +++ b/spec/doubly_linked_list.js @@ -0,0 +1,118 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import DoublyLinkedList from '../src/doubly_linked_list' + +chai.use(chaiChange) + +describe('DoublyLinkedList', function() { + 'use strict' + + it('is a function', function() { + expect(DoublyLinkedList).to.be.a('function') + }) + + context('empty list interrogation', function() { + const emptyList = new DoublyLinkedList() + it('getHeadNode() returns null', function() { + expect(emptyList.getHeadNode()).to.be.null + }) + it('getTailNode() returns null', function() { + expect(emptyList.getTailNode()).to.be.null + }) + it('isEmpty() returns true', function() { + expect(emptyList.isEmpty()).to.be.true + }) + it('size() returns 0', function() { + expect(emptyList.size()).to.be.equal(0) + }) + it('contains("x") returns false', function() { + expect(emptyList.contains('x')).to.be.false + }) + it('find("x") returns -1', function() { + expect(emptyList.find('x')).to.be.equal(-1) + }) + }) + + context('non-empty list interrogation', function() { + const dlList = new DoublyLinkedList() + dlList.insert('bad') + dlList.insert('ok') + dlList.insert('good') + it('the element getHeadNode() returns has data “bad”', function() { + expect(dlList.getHeadNode().getData()).to.be.equal('bad') + }) + it('the element getTailNode() returns has data “good”', function() { + expect(dlList.getTailNode().getData()).to.be.equal('good') + }) + it('contains("ok") returns true', function() { + expect(dlList.contains('ok')).to.be.true + }) + it('contains("mediocre") returns false', function() { + expect(dlList.contains('mediocre')).to.be.false + }) + it('find("ok") returns a node with data “ok”', function() { + expect(dlList.find('ok').getData()).to.be.equal('ok') + }) + it('find("mediocre") returns -1', function() { + expect(dlList.find('mediocre')).to.be.equal(-1) + }) + it('isEmpty() returns false', function() { + expect(dlList.isEmpty()).to.be.false + }) + it('size() returns 3', function() { + expect(dlList.size()).to.be.equal(3) + }) + }) + + context('list manipulation', function() { + const dlList = new DoublyLinkedList() + dlList.insert('bad') + dlList.insert('ok') + dlList.insert('good') + dlList.insertFirst('horrible') + it(('insertFirst() changes the head (first) element'), function() { + expect(dlList.getHeadNode().getData()).to.be.equal('horrible') + }) + it('insertFirst() does not change the tail (last) element', function() { + expect(dlList.getTailNode().getData()).to.be.equal('good') + }) + it('no element has data “mediocre”', function() { + expect(dlList.contains('mediocre')).to.be.false + }) + it('insertBefore() inserts an element where specified', function() { + dlList.insertBefore('ok', 'mediocre') + expect(dlList.contains('mediocre')).to.be.true + }) + it('insertBefore() inserts nothing if no target exists', function() { + const dlSizeOld = dlList.size(); + dlList.insertBefore('stupendous', 'superb') + expect(dlList.size()).to.be.equal(dlSizeOld) + }) + it('insertAfter() not after the last element does not change it', function() { + dlList.insertAfter('horrible', 'lousy') + expect(dlList.getTailNode().getData()).to.be.equal('good') + }) + it('insertAfter() after the last element changes it', function() { + dlList.insertAfter('good', 'excellent') + expect(dlList.getTailNode().getData()).to.be.equal('excellent') + }) + it('insertAfter() inserts nothing if no target exists', function() { + const dlSizeOld = dlList.size(); + dlList.insertAfter('superb', 'stupendous') + expect(dlList.size()).to.be.equal(dlSizeOld) + }) + it('remove() changes the tail (last) element', function() { + dlList.remove() + expect(dlList.getTailNode().getData()).to.be.equal('good') + }) + it('removeFirst() changes the head (first) element', function() { + dlList.removeFirst() + expect(dlList.getHeadNode().getData()).to.be.equal('lousy') + }) + it('clear() makes the list’s size 0', function() { + dlList.clear() + expect(dlList.size()).to.be.equal(0) + }) + }) + +}) diff --git a/spec/priority_node.js b/spec/priority_node.js index d27c57b..8d9cfd2 100644 --- a/spec/priority_node.js +++ b/spec/priority_node.js @@ -4,14 +4,14 @@ import PriorityNode from '../src/priority_node' chai.use(chaiChange) -describe('PriorityNode', () => { +describe('PriorityNode', function() { 'use strict' - it('is a function', () => { + it('is a function', function() { expect(PriorityNode).to.be.a('function') }) - context('getData()', () => { + context('getData()', function() { const levelZero = new PriorityNode({data: 'level0', priority: 0}) const level0 = new PriorityNode({data: 0, priority: 0}) const levelArrayNum = new PriorityNode({data: [1, 2], priority: 0}) @@ -22,165 +22,167 @@ describe('PriorityNode', () => { const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) - it('returns the correct type, if a string', () => { + it('returns the correct type, if a string', function() { expect(levelZero.getData()).to.be.a('string') }) - it('returns the correct value, if a string', () => { + it('returns the correct value, if a string', function() { expect(levelZero.getData()).to.be.equal('level0') }) - it('returns the correct type, if a number', () => { + it('returns the correct type, if a number', function() { expect(level0.getData()).to.be.a('number') }) - it('returns the correct value, if a number', () => { + it('returns the correct value, if a number', function() { expect(level0.getData()).to.be.equal(0) }) - it('returns the correct type, if an array', () => { + it('returns the correct type, if an array', function() { expect(Array.isArray(levelArrayNum.getData())).to.be.true }) - it('returns the correct value, if an array', () => { + it('returns the correct value, if an array', function() { expect(levelArrayString.getData()).to.be.deep.equal(['a', 'b']) }) - it('returns the correct type, if an object', () => { + it('returns the correct type, if an object', function() { expect(levelObj.getData()).to.be.an('object') }) - it('returns the correct value, if an object', () => { + it('returns the correct value, if an object', function() { expect(levelObj.getData()).to.be.deep.equal({'a': 1, 'b': 2}) }) - it('returns an object with a retrievable property, if an object', () => { + it('returns an object with a retrievable property, if an object', function() { expect(levelObj.getData().a).to.be.equal(1) }) - it('returns the correct value, if priority is unspecified', () => { + it('returns the correct value, if priority is unspecified', function() { expect(priUnd.getData()).to.be.equal('level0') }) - it('returns the correct value, if priority is unspecified', () => { + it('returns the correct value, if priority is unspecified', function() { expect(priUnd.getData()).to.be.equal('level0') }) - it('returns the correct value, if next node is specified', () => { + it('returns the correct value, if next node is specified', function() { expect(next00.getData()).to.be.equal(-1) }) - it('returns undefined, if unspecified', () => { + it('returns undefined, if unspecified', function() { expect(levelUnd.getData()).to.be.undefined }) - it('returns undefined, if priority is not a number', () => { + it('returns undefined, if priority is not a number', function() { expect(levZPriZ.getData()).to.be.undefined }) - it('returns undefined, if next is not a PriorityNode', () => { + it('returns undefined, if next is not a PriorityNode', function() { expect(next0Num.getData()).to.be.undefined }) }) - context('getPriority()', () => { + context('getPriority()', function() { const level0 = new PriorityNode({data: 0, priority: 0}) const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) const priUnd = new PriorityNode({data: 'level0'}) const levelUnd = new PriorityNode({priority: 0}) const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) - it('returns the correct type', () => { + it('returns the correct type', function() { expect(level0.getPriority()).to.be.a('number') }) - it('returns the correct value', () => { + it('returns the correct value', function() { expect(level0.getPriority()).to.be.equal(0) }) - it('returns the correct value, if next node is specified', () => { + it('returns the correct value, if next node is specified', function() { expect(next00.getPriority()).to.be.equal(0) }) - it('returns the default value, if unspecified', () => { + it('returns the default value, if unspecified', function() { expect(priUnd.getPriority()).to.be.equal(0) }) - it('returns undefined, if data unspecified', () => { + it('returns undefined, if data unspecified', function() { expect(levelUnd.getPriority()).to.be.undefined }) - it('returns undefined, if not a number', () => { + it('returns undefined, if not a number', function() { expect(levZPriZ.getPriority()).to.be.undefined }) - it('returns undefined, if next is not a PriorityNode', () => { + it('returns undefined, if next is not a PriorityNode', function() { expect(next0Num.getPriority()).to.be.undefined }) }) - context('getNext()', () => { + context('getNext()', function() { const level0 = new PriorityNode({data: 0, priority: 0}) const next00 = new PriorityNode({data: -1, priority: 0, next: level0}) const next0Num = new PriorityNode({data: -1, priority: 0, next: 0}) const levelUnd = new PriorityNode({priority: 0}) const levZPriZ = new PriorityNode({data: 'level0', priority: 'zero'}) - it('returns the correct type, if specified', () => { + it('returns the correct type, if specified', function() { expect(next00.getNext() instanceof PriorityNode).to.be.true }) - it('returns the correct value, if specified', () => { - expect(next00.getNext()).to.be.equal(level0) + it('returns the correct value, if specified', function() { + expect(next00.getNext()).to.be.deep.equal(level0) }) it( 'returns a PriorityNode with a retrievable property, if specified', - () => { + function() { expect(next00.getNext().getData()).to.be.equal(0) } ) - it('returns null, if unspecified', () => { + it('returns null, if unspecified', function() { expect(level0.getNext()).to.be.null }) - it('returns null, if specified but not a PriorityNode', () => { + it('returns null, if specified but not a PriorityNode', function() { expect(next0Num.getNext()).to.be.null }) - it('returns null, if data is unspecified', () => { + it('returns null, if data is unspecified', function() { expect(levelUnd.getNext()).to.be.null }) - it('returns null, if priority is not a number', () => { + it('returns null, if priority is not a number', function() { expect(levZPriZ.getNext()).to.be.null }) }) - context('setPriority()', () => { + + context('setPriority()', function() { const level0 = new PriorityNode({data: 0, priority: 0}) - it('returns a PriorityNode', () => { + it('returns a PriorityNode', function() { expect(level0.setPriority(2) instanceof PriorityNode).to.be.true }) - it('returns the correct PriorityNode', () => { + it('returns the correct PriorityNode', function() { expect(level0.setPriority(3)).to.be.deep.equal(level0) }) it( - 'returns the PriorityNode with a retrievable data property', - () => { + 'returns a PriorityNode with a retrievable data property', + function() { expect(level0.setPriority(4).getData()).to.be.equal(0) } ) it( - 'returns the PriorityNode with a retrievable new priority property', - () => { + 'returns a PriorityNode with a retrievable new priority property', + function() { expect(level0.setPriority(5).getPriority()).to.be.equal(5) } ) it( 'fails to change priority (from last value), if newPriority is invalid', - () => { + function() { expect(level0.setPriority("6").getPriority()).to.be.equal(5) } ) }) - context('setNext()', () => { + + context('setNext()', function() { const level0 = new PriorityNode({data: 0, priority: 0}) const levelZero = new PriorityNode({data: 'level0', priority: 0}) - it('returns a PriorityNode', () => { + it('returns a PriorityNode', function() { expect(level0.setNext(levelZero) instanceof PriorityNode).to.be.true }) - it('returns the correct PriorityNode', () => { + it('returns the correct PriorityNode', function() { expect(level0.setNext(levelZero)).to.be.deep.equal(level0) }) it( - 'returns the PriorityNode with a retrievable priority property', - () => { + 'returns a PriorityNode with a retrievable priority property', + function() { expect(level0.setNext(levelZero).getPriority()).to.be.equal(0) } ) it( - 'returns the PriorityNode with a retrievable new next property', - () => { + 'returns a PriorityNode with a retrievable new next property', + function() { expect(level0.setNext(levelZero).getNext()).to.be.deep.equal(levelZero) } ) it( 'fails to change next (from last value), if newNext is invalid', - () => { + function() { expect(level0.setNext("next00").getNext()).to.be.deep.equal(levelZero) } ) diff --git a/spec/priority_queue.js b/spec/priority_queue.js index 94d1a41..2c9ee87 100644 --- a/spec/priority_queue.js +++ b/spec/priority_queue.js @@ -4,66 +4,66 @@ import PriorityQueue from '../src/priority_queue' chai.use(chaiChange) -describe('PriorityQueue', () => { +describe('PriorityQueue', function() { 'use strict' - it('is a function', () => { + it('is a function', function() { expect(PriorityQueue).to.be.a('function') }) - context('empty queue', () => { + context('empty queue', function() { const emptyQueue = new PriorityQueue() - it('front() returns null', () => { + it('front() returns null', function() { expect(emptyQueue.front()).to.be.null }) - it('back() returns null', () => { + it('back() returns null', function() { expect(emptyQueue.back()).to.be.null }) - it('isEmpty() returns true', () => { + it('isEmpty() returns true', function() { expect(emptyQueue.isEmpty()).to.be.true }) - it('length() returns 0', () => { + it('length() returns 0', function() { expect(emptyQueue.length()).to.be.equal(0) }) - it('dequeue() returns null', () => { + it('dequeue() returns null', function() { expect(emptyQueue.dequeue()).to.be.null }) }) - context('non-empty queue', () => { + context('non-empty queue', function() { const pQueue = new PriorityQueue() pQueue.enqueue('bad', 10) pQueue.enqueue('ok', 50) pQueue.enqueue('good', 90) - it('the element front() returns has priority 90', () => { + it('the element front() returns has priority 90', function() { expect(pQueue.front().getPriority()).to.be.equal(90) }) - it('the element front() returns has data “good”', () => { + it('the element front() returns has data “good”', function() { expect(pQueue.front().getData()).to.be.equal('good') }) - it('the element back() returns has priority 10', () => { + it('the element back() returns has priority 10', function() { expect(pQueue.back().getPriority()).to.be.equal(10) }) - it('isEmpty() returns false', () => { + it('isEmpty() returns false', function() { expect(pQueue.isEmpty()).to.be.false }) - it('length() returns 3', () => { + it('length() returns 3', function() { expect(pQueue.length()).to.be.equal(3) }) - it('the element dequeue() returns has priority 90', () => { + it('the element dequeue() returns has priority 90', function() { expect(pQueue.dequeue().getPriority()).to.be.equal(90) }) - it('the length is 2 after 1 dequeuing', () => { + it('the length is 2 after 1 dequeuing', function() { expect(pQueue.length()).to.be.equal(2) }) - it('the highest priority is 50 after 1 dequeuing', () => { + it('the highest priority is 50 after 1 dequeuing', function() { expect(pQueue.front().getPriority()).to.be.equal(50) }) - it('the length is 3 after a valid enqueuing', () => { + it('the length is 3 after a valid enqueuing', function() { pQueue.enqueue('horrible', 0); expect(pQueue.length()).to.be.equal(3) }) - it('the length stays 3 after an invalid enqueuing', () => { + it('the length stays 3 after an invalid enqueuing', function() { pQueue.enqueue('wonderful', '100'); expect(pQueue.length()).to.be.equal(3) }) diff --git a/src/double_node.js b/src/double_node.js new file mode 100644 index 0000000..4139aba --- /dev/null +++ b/src/double_node.js @@ -0,0 +1,53 @@ +'use strict' + +/* + Class declaration for DoubleNode and export statement making that + object the default export from this module. +*/ +export default class DoubleNode { + constructor(nodeProps) { + // If the argument is valid: + if ( + nodeProps !== undefined + && nodeProps.data !== undefined + && ( + nodeProps.next === undefined + || nodeProps.next instanceof DoubleNode + ) + && ( + nodeProps.previous === undefined + || nodeProps.previous instanceof DoubleNode + ) + ) { + this.data = nodeProps.data; + this.next = nodeProps.next; + this.previous = nodeProps.previous; + } + } + // Returns the node’s data. + getData() { + return this.data; + } + // Returns the next node, or null if none. + getNext() { + return this.next || null; + } + // Changes the next node, if specified, and returns this node. + setNext(newNext) { + if (newNext instanceof DoubleNode) { + this.next = newNext; + } + return this; + } + // Returns the previous node, or null if none. + getPrevious() { + return this.previous || null; + } + // Changes the previous node, if specified, and returns this node. + setPrevious(newPrevious) { + if (newPrevious instanceof DoubleNode) { + this.previous = newPrevious; + } + return this; + } +} diff --git a/src/doubly_linked_list.js b/src/doubly_linked_list.js new file mode 100644 index 0000000..097f88e --- /dev/null +++ b/src/doubly_linked_list.js @@ -0,0 +1,137 @@ +'use strict'; +import DoubleNode from './double_node'; + +/* + Class declaration for DoublyLinkedList and export statement making that + object the default export from this module. +*/ +export default class DoublyLinkedList { + constructor() { + this.list = []; + } + + // UTILITY METHODS + + /* + Returns the index of the first element with a data value identical to + the specified one, or -1 if no such element exists. “First” = having the + smallest index. The array contains the nodes, with the head (first) node + at index 0. + */ + firstMatchIndex(data) { + let fmIndex = 0; + while (fmIndex < this.list.length) { + if (this.list[fmIndex].getData() === data) { + return fmIndex; + } + else { + fmIndex++; + } + } + return -1; + } + + // INTERROGATION METHODS + + // Returns the head (first) node. + getHeadNode() { + return this.list[0] || null; + } + + // Returns the tail (last) node. + getTailNode() { + return this.list[this.list.length - 1] || null; + } + + /* + Returns whether the list contains an element with the specified data + value. + */ + contains(data) { + return this.firstMatchIndex(data) > -1; + } + + /* + Returns the first node containing an element with the specified data + value. + */ + find(data) { + return this.list[this.firstMatchIndex(data)] || -1; + } + + // Returns whether the list is empty. + isEmpty() { + return this.list.length === 0; + } + + // Returns the length of the list. + size() { + return this.list.length; + } + + // MANIPULATION METHODS + + // Adds a specified element at the tail (as the last element). + insert(d) { + if (d !== undefined) { + const newNode = new DoubleNode({data: d}); + this.list.push(newNode); + } + } + + // Adds a specified element at the head (as the first element). + insertFirst(d) { + if (d !== undefined) { + const newNode = new DoubleNode({data: d}); + this.list.unshift(newNode); + } + } + + /* + Adds a specified element before the first element with a specified + data value. + */ + insertBefore(d, n) { + if (d !== undefined && n !== undefined) { + const fmIndex = this.firstMatchIndex(d); + if (fmIndex > -1) { + const newNode = new DoubleNode({data: n}); + this.list.splice(fmIndex, 0, newNode); + } + } + } + + /* + Adds a specified element after the first element with a specified + data value. + */ + insertAfter(d, n) { + if (d !== undefined && n !== undefined) { + const fmIndex = this.firstMatchIndex(d); + if (fmIndex > -1) { + const newNode = new DoubleNode({data: n}); + this.list.splice(fmIndex + 1, 0, newNode); + } + } + } + + /* + Deletes the last (tail) element. + */ + remove() { + this.list.pop(); + } + + /* + Deletes the first (head) element. + */ + removeFirst() { + this.list.shift(); + } + + // Deletes all elements. + clear() { + this.list.splice(0); + } + +} diff --git a/src/node2.js b/src/node2.js new file mode 100644 index 0000000..e5d4f2c --- /dev/null +++ b/src/node2.js @@ -0,0 +1,36 @@ +'use strict' + +/* + Class declaration for Node and export statement making that + object the default export from this module. +*/ +export default class Node { + constructor(nodeProps) { + // If the argument is valid: + if ( + nodeProps.data !== undefined + && ( + nodeProps.next === undefined + || nodeProps.next instanceof Node + ) + ) { + this.data = nodeProps.data; + this.next = nodeProps.next; + } + } + // Returns the node’s data. + getData() { + return this.data; + } + // Returns the next node, or null if none. + getNext() { + return this.next || null; + } + // Changes the next node, if specified, and returns this node. + setNext(newNext) { + if (newNext instanceof PriorityNode) { + this.next = newNext; + } + return this; + } +} From 0bff4f60787b996c92f5ead57e8c9163a7b658b8 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Wed, 17 May 2017 22:42:47 -0700 Subject: [PATCH 26/38] Created tests for set interrogation (not yet set manipulation). --- spec/set.js | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 spec/set.js diff --git a/spec/set.js b/spec/set.js new file mode 100644 index 0000000..48f2c6b --- /dev/null +++ b/spec/set.js @@ -0,0 +1,81 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Set from '../src/set' + +chai.use(chaiChange) + +describe('Set', function() { + 'use strict' + + it('is a function', function() { + expect(Set).to.be.a('function') + }) + + context('empty set interrogation', function() { + const emptySet = new Set([]) + it('isEmpty() returns true', function() { + expect(emptySet.isEmpty()).to.be.true + }) + it('contains("x") returns false', function() { + expect(emptySet.contains('x')).to.be.false + }) + it('size() returns 0', function() { + expect(emptySet.size()).to.be.equal(0) + }) + }) + + context('non-empty set interrogation', function() { + const set = new Set([1, 2, 4, 8, 16]) + it('isEmpty() returns false', function() { + expect(set.isEmpty()).to.be.false + }) + it('contains(4) returns true', function() { + expect(set.contains(4)).to.be.true + }) + it('contains(5) returns false', function() { + expect(set.contains(5)).to.be.false + }) + it('size() returns 5', function() { + expect(set.size()).to.be.equal(5) + }) + }) + + context('dual-set interrogation', function() { + const set0 = new Set([3, 6, 9, 12, 15]) + const set1 = new Set([3, 6, 12, 24]) + it(('set0.union(set1) returns a set of 6 elements'), function() { + expect(set0.union(set1).size()).to.be.equal(6) + }) + it(('set0.union(set1) returns a set containing 15'), function() { + expect(set0.union(set1).contains(15)).to.be.true + }) + it(('set0.intersect(set1) returns a set of 3 elements'), function() { + expect(set0.intersect(set1).size()).to.be.equal(3) + }) + it(('set0.intersect(set1) returns a set containing 6'), function() { + expect(set0.intersect(set1).contains(6)).to.be.true + }) + it(('set0.intersect(set1) returns a set not containing 9'), function() { + expect(set0.intersect(set1).contains(9)).to.be.false + }) + it(('set0.difference(set1) returns a set of 2 elements'), function() { + expect(set0.intersect(set1).size()).to.be.equal(2) + }) + it(('set0.difference(set1) returns a set containing 9'), function() { + expect(set0.intersect(set1).contains(9)).to.be.true + }) + it(('set0.difference(set1) returns a set not containing 6'), function() { + expect(set0.intersect(set1).contains(6)).to.be.false + }) + it(('set1.difference(set0) returns a set of 1 element'), function() { + expect(set0.intersect(set1).size()).to.be.equal(2) + }) + it(('set1.difference(set0) returns a set containing 24'), function() { + expect(set0.intersect(set1).contains(24)).to.be.true + }) + it(('set1.difference(set0) returns a set not containing 6'), function() { + expect(set0.intersect(set1).contains(6)).to.be.false + }) + }) + +}) From aa33baac746320c35b3c6e54683e8bdcc4dbb3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Thu, 18 May 2017 08:47:42 -0700 Subject: [PATCH 27/38] pass all tests except insertAfter --- spec/linkedListTest.js | 40 ++++++++++++++++++++++++++- src/linkedList.js | 62 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index b970f0b..0e9d243 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -60,11 +60,49 @@ describe.only('LinkedList', () => { context( 'insertBefore', () => { it( 'inserts a node before a specified node', () => { list.insertBefore( 'bananas', 'apples' ) - console.log(list) expect( list.head.next.data ).to.equal( 'bananas' ) }) }) + context( 'insertfAter', () => { + it( 'inserts a node after a specified node', () => { + list.insertAfter( 'apples', 'guava' ) + expect( list.head.next.next.next.data ).to.equal( 'guava') + }) + }) + + context( 'remove()', () => { + it( 'removes the tail node from the list', () => { + list.remove() + expect( list.length ).to.equal(5) + }) + }) + + context( 'removeFirst()', () => { + it( 'removes the head node from the list' , () => { + list.removeFirst() + console.log(list) + expect( list.head.data ).to.equal( 'bananas' ) + }) + }) + + context( 'isEmpty()', () => { + it( ' determines whether the list is empty', () => { + expect( list.isEmpty() ).to.equal(false) + }) + }) + context( 'size()', () => { + it( 'returns the size of the list', () => { + expect( list.size() ).to.equal(5) + }) + }) + + context( 'clear()', () => { + it( ' clears the list of all nodes and data', () => { + list.clear() + expect( list.length ).to.equal(0) + }) + }) }) diff --git a/src/linkedList.js b/src/linkedList.js index b2c01e8..bff5815 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -89,7 +89,6 @@ export default class LinkedList { this.head = newNode return } - if ( currentNode.next.data == target ) { newNode.next = currentNode.next currentNode.next = newNode @@ -105,4 +104,65 @@ export default class LinkedList { } this.length++ } + + insertAfter( target, data){ + let newNode = new Node( data ) + let currentNode = this.head + + if ( this.length == 1 ) { + currenrNode.next = newNode + } + + while ( currentNode ) { + if ( currentNode.data == target) { + newNode.next = currentNode.next + currentNode.next = newNode + return + } + if ( currentNode == this.tail ){ + return 'No fruit' + } + else { + currentNode = currentNode.next + } + } + this.length++ + } + + remove() { + let currentNode = this.head + while( currentNode.next ) { + if( currentNode.next === this.tail){ + currentNode = this.tail + currentNode.next = null + } + this.length + return + } + currentNode = currentNode + } + + removeFirst() { + let currentNode = this.head + this.head = currentNode.next + this.length + return + } + + isEmpty() { + if ( this.head == null) { + return true + } + return false + } + + size() { + return this.length + } + + clear() { + this.tail = null + this.head = this.tail + this.length = 0 + } } From 96dbeeb299a74ae30557fd42b20e65dbecc981e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Thu, 18 May 2017 09:40:34 -0700 Subject: [PATCH 28/38] all tests passing --- spec/linkedListTest.js | 3 +-- src/linkedList.js | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 0e9d243..994efa2 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -67,7 +67,7 @@ describe.only('LinkedList', () => { context( 'insertfAter', () => { it( 'inserts a node after a specified node', () => { list.insertAfter( 'apples', 'guava' ) - expect( list.head.next.next.next.data ).to.equal( 'guava') + expect( list.head.next.next.next.data ).to.equal( 'banana') }) }) @@ -81,7 +81,6 @@ describe.only('LinkedList', () => { context( 'removeFirst()', () => { it( 'removes the head node from the list' , () => { list.removeFirst() - console.log(list) expect( list.head.data ).to.equal( 'bananas' ) }) }) diff --git a/src/linkedList.js b/src/linkedList.js index bff5815..5d18e91 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -110,12 +110,12 @@ export default class LinkedList { let currentNode = this.head if ( this.length == 1 ) { - currenrNode.next = newNode + currentNode.next = newNode } while ( currentNode ) { if ( currentNode.data == target) { - newNode.next = currentNode.next + newNode = currentNode.next currentNode.next = newNode return } From 2610d76e0adec718a91c110ffd8db4598bedc110 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Thu, 18 May 2017 14:17:23 -0700 Subject: [PATCH 29/38] Renamed Set to PowerSet to avoid conflict with JS Set built-in. Finished developing, testing, and debugging PowerSet. --- spec/power_set.js | 144 ++++++++++++++++++++++++++++++++++++++ spec/set.js | 81 --------------------- src/doubly_linked_list.js | 8 +-- src/power_set.js | 101 ++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 87 deletions(-) create mode 100644 spec/power_set.js delete mode 100644 spec/set.js create mode 100644 src/power_set.js diff --git a/spec/power_set.js b/spec/power_set.js new file mode 100644 index 0000000..8ce0118 --- /dev/null +++ b/spec/power_set.js @@ -0,0 +1,144 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import PowerSet from '../src/power_set' + +chai.use(chaiChange) + +describe('PowerSet', function() { + 'use strict' + + it('is a function', function() { + expect(PowerSet).to.be.a('function') + }) + + context('empty powerSet interrogation', function() { + const emptyPowerSet = new PowerSet([]) + it('isEmpty() returns true', function() { + expect(emptyPowerSet.isEmpty()).to.be.true + }) + it('contains("x") returns false', function() { + expect(emptyPowerSet.contains('x')).to.be.false + }) + it('size() returns 0', function() { + expect(emptyPowerSet.size()).to.equal(0) + }) + }) + + context('non-empty powerSet interrogation', function() { + const powerSet = new PowerSet([1, 2, 4, 8, 16]) + it('isEmpty() returns false', function() { + expect(powerSet.isEmpty()).to.be.false + }) + it('contains(4) returns true', function() { + expect(powerSet.contains(4)).to.be.true + }) + it('contains(5) returns false', function() { + expect(powerSet.contains(5)).to.be.false + }) + it('size() returns 5', function() { + expect(powerSet.size()).to.equal(5) + }) + }) + + context('dual-set interrogation', function() { + const ps0 = new PowerSet([3, 6, 9, 12, 15]) + const ps1 = new PowerSet([3, 6, 12, 24]) + it(('ps0.union(ps1) returns a powerSet of 6 elements'), function() { + expect(ps0.union(ps1).size()).to.equal(6) + }) + it(('ps0.union(ps1) returns a powerSet containing 15'), function() { + expect(ps0.union(ps1).contains(15)).to.be.true + }) + it(('ps0.union(ps0) returns a powerSet containing 15'), function() { + expect(ps1.union(ps0).contains(15)).to.be.true + }) + it(('ps0.intersect(ps1) returns a powerSet of 3 elements'), function() { + expect(ps0.intersect(ps1).size()).to.equal(3) + }) + it(('ps0.intersect(ps1) returns a powerSet containing 6'), function() { + expect(ps0.intersect(ps1).contains(6)).to.be.true + }) + it(('ps0.intersect(ps1) returns a powerSet not containing 9'), function() { + expect(ps0.intersect(ps1).contains(9)).to.be.false + }) + it(('ps1.intersect(ps0) returns a powerSet of 3 elements'), function() { + expect(ps1.intersect(ps0).size()).to.equal(3) + }) + it(('ps1.intersect(ps0) returns a powerSet containing 6'), function() { + expect(ps1.intersect(ps0).contains(6)).to.be.true + }) + it(('ps1.intersect(ps0) returns a powerSet not containing 9'), function() { + expect(ps1.intersect(ps0).contains(9)).to.be.false + }) + it(('ps0.difference(ps1) returns a powerSet of 2 elements'), function() { + expect(ps0.difference(ps1).size()).to.equal(2) + }) + it(('ps0.difference(ps1) returns a powerSet containing 9'), function() { + expect(ps0.difference(ps1).contains(9)).to.be.true + }) + it(('ps0.difference(ps1) returns a powerSet not containing 6'), function() { + expect(ps0.difference(ps1).contains(6)).to.be.false + }) + it(('ps1.difference(ps0) returns a powerSet of 1 element'), function() { + expect(ps1.difference(ps0).size()).to.equal(1) + }) + it(('ps1.difference(ps0) returns a powerSet containing 24'), function() { + expect(ps1.difference(ps0).contains(24)).to.be.true + }) + it(('ps1.difference(ps0) returns a powerSet not containing 6'), function() { + expect(ps1.difference(ps0).contains(6)).to.be.false + }) + }) + + context('set manipulation', function() { + const powerSet = new PowerSet([1, 2, 4, 8, 16]) + it('add() increases the powerSet size', function() { + const oldSize = powerSet.size() + powerSet.add(32) + expect(powerSet.size()).to.equal(oldSize + 1) + }) + it('adding an existing element makes no change', function() { + const oldSize = powerSet.size() + powerSet.add(4) + expect(powerSet.size()).to.equal(oldSize) + }) + it('add() makes the powerSet contain the added element', function() { + expect(powerSet.contains(64)).to.be.false + powerSet.add(64) + expect(powerSet.contains(64)).to.be.true + }) + it('remove() decreases the powerSet size', function() { + const oldSize = powerSet.size() + powerSet.remove(64) + expect(powerSet.size()).to.equal(oldSize - 1) + }) + it('removing a nonexistent element makes no change', function() { + const oldSize = powerSet.size() + powerSet.remove(33) + expect(powerSet.size()).to.equal(oldSize) + }) + it('remove() makes the powerSet omit the removed element', function() { + expect(powerSet.contains(32)).to.be.true + powerSet.remove(32) + expect(powerSet.contains(32)).to.be.false + }) + it('clone() returns a distinct identical powerSet', function() { + const newPowerSet = powerSet.clone() + expect(newPowerSet).to.not.equal(powerSet) + expect(newPowerSet).to.deep.equal(powerSet) + }) + }) + + context('element iteration', function() { + const powerSet = new PowerSet([1, 2, 4, 8, 16]) + const newPowerSet = new PowerSet([]) + it('forEach() can add 1 to each element', function() { + const plusOne = function(value, key, thisArg) { + newPowerSet.add(value + 1); + } + powerSet.forEach(element => plusOne(element)) + expect(newPowerSet.contains(8)).to.be.false + expect(newPowerSet.contains(9)).to.be.true + }) + }) +}) diff --git a/spec/set.js b/spec/set.js deleted file mode 100644 index 48f2c6b..0000000 --- a/spec/set.js +++ /dev/null @@ -1,81 +0,0 @@ -import chai, { expect } from 'chai' -import chaiChange from 'chai-change' -import Set from '../src/set' - -chai.use(chaiChange) - -describe('Set', function() { - 'use strict' - - it('is a function', function() { - expect(Set).to.be.a('function') - }) - - context('empty set interrogation', function() { - const emptySet = new Set([]) - it('isEmpty() returns true', function() { - expect(emptySet.isEmpty()).to.be.true - }) - it('contains("x") returns false', function() { - expect(emptySet.contains('x')).to.be.false - }) - it('size() returns 0', function() { - expect(emptySet.size()).to.be.equal(0) - }) - }) - - context('non-empty set interrogation', function() { - const set = new Set([1, 2, 4, 8, 16]) - it('isEmpty() returns false', function() { - expect(set.isEmpty()).to.be.false - }) - it('contains(4) returns true', function() { - expect(set.contains(4)).to.be.true - }) - it('contains(5) returns false', function() { - expect(set.contains(5)).to.be.false - }) - it('size() returns 5', function() { - expect(set.size()).to.be.equal(5) - }) - }) - - context('dual-set interrogation', function() { - const set0 = new Set([3, 6, 9, 12, 15]) - const set1 = new Set([3, 6, 12, 24]) - it(('set0.union(set1) returns a set of 6 elements'), function() { - expect(set0.union(set1).size()).to.be.equal(6) - }) - it(('set0.union(set1) returns a set containing 15'), function() { - expect(set0.union(set1).contains(15)).to.be.true - }) - it(('set0.intersect(set1) returns a set of 3 elements'), function() { - expect(set0.intersect(set1).size()).to.be.equal(3) - }) - it(('set0.intersect(set1) returns a set containing 6'), function() { - expect(set0.intersect(set1).contains(6)).to.be.true - }) - it(('set0.intersect(set1) returns a set not containing 9'), function() { - expect(set0.intersect(set1).contains(9)).to.be.false - }) - it(('set0.difference(set1) returns a set of 2 elements'), function() { - expect(set0.intersect(set1).size()).to.be.equal(2) - }) - it(('set0.difference(set1) returns a set containing 9'), function() { - expect(set0.intersect(set1).contains(9)).to.be.true - }) - it(('set0.difference(set1) returns a set not containing 6'), function() { - expect(set0.intersect(set1).contains(6)).to.be.false - }) - it(('set1.difference(set0) returns a set of 1 element'), function() { - expect(set0.intersect(set1).size()).to.be.equal(2) - }) - it(('set1.difference(set0) returns a set containing 24'), function() { - expect(set0.intersect(set1).contains(24)).to.be.true - }) - it(('set1.difference(set0) returns a set not containing 6'), function() { - expect(set0.intersect(set1).contains(6)).to.be.false - }) - }) - -}) diff --git a/src/doubly_linked_list.js b/src/doubly_linked_list.js index 097f88e..6e9c667 100644 --- a/src/doubly_linked_list.js +++ b/src/doubly_linked_list.js @@ -115,16 +115,12 @@ export default class DoublyLinkedList { } } - /* - Deletes the last (tail) element. - */ + // Deletes the last (tail) element. remove() { this.list.pop(); } - /* - Deletes the first (head) element. - */ + // Deletes the first (head) element. removeFirst() { this.list.shift(); } diff --git a/src/power_set.js b/src/power_set.js new file mode 100644 index 0000000..3774b87 --- /dev/null +++ b/src/power_set.js @@ -0,0 +1,101 @@ +'use strict'; + +/* + Class declaration for PowerSet, with a default constructor, and export + statement making that object the default export from this module. +*/ +export default class PowerSet { + constructor(iterableObject) { + this.pSet = new Set(iterableObject); + } + + // INTERROGATION METHODS + + // Returns whether the powerSet is empty. + isEmpty() { + return this.pSet.size === 0; + } + + // Returns whether the powerSet contains the specified element. + contains(value) { + return this.pSet.has(value); + } + + // Returns the count of elements. + size() { + return this.pSet.size; + } + + // DUAL-SET INTERROGATION METHODS + + // Returns the union of this and another powerSet. + union(otherPowerSet) { + const newPowerSet = new PowerSet(this.pSet); + const addToThis = function(element, key, sourceSet) { + this.add(element); + }; + otherPowerSet.pSet.forEach(addToThis, newPowerSet.pSet); + return newPowerSet; + } + + // Returns the intersection of this and another powerSet. + intersect(otherPowerSet) { + const newPowerSet = new PowerSet(); + const addToThis = function(element, key, thisSet) { + if (otherPowerSet.contains(element)) { + this.add(element); + } + }; + this.pSet.forEach(addToThis, newPowerSet.pSet); + return newPowerSet; + } + + // Returns the difference of this from another powerSet. + difference(otherPowerSet) { + const newPowerSet = new PowerSet(); + const addToThis = function(element, key, thisSet) { + if (! otherPowerSet.contains(element)) { + this.add(element); + } + }; + this.pSet.forEach(addToThis, newPowerSet.pSet); + return newPowerSet; + } + + // Returns whether this is a subset of another powerSet. + isSubset(otherPowerSet) { + for (element of this.pSet) { + if (! otherPowerSet.contains(element)) { + return false; + } + } + return true; + } + + // MANIPULATION METHODS + + // Adds a specified element, if not already in the PowerSet. + add(value) { + if (value !== undefined) { + this.pSet.add(value); + } + } + + // Removes a specified element, if in the PowerSet. + remove(value) { + this.pSet.delete(value); + } + + // Returns a copy of the PowerSet. + clone() { + return new PowerSet(this.pSet); + } + + // ELEMENT ITERATION METHODS + + // Executes a specified function on each element. + forEach(fn) { + this.pSet.forEach(fn, this.pSet); + } + +} From d54119a14d94db51f963db5f198b6a2ecd5b4994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Thu, 18 May 2017 15:05:12 -0700 Subject: [PATCH 30/38] pass all tests --- spec/linkedListTest.js | 2 +- spec/set.js | 81 ------------------------------------------ 2 files changed, 1 insertion(+), 82 deletions(-) delete mode 100644 spec/set.js diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 994efa2..f80eff5 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -5,7 +5,7 @@ import LinkedList from '../src/linkedList' chai.use(chaiChange) -describe.only('LinkedList', () => { +describe('LinkedList', () => { 'use strict' const list = new LinkedList() list.insert( {data: 'apple'} ) diff --git a/spec/set.js b/spec/set.js deleted file mode 100644 index 48f2c6b..0000000 --- a/spec/set.js +++ /dev/null @@ -1,81 +0,0 @@ -import chai, { expect } from 'chai' -import chaiChange from 'chai-change' -import Set from '../src/set' - -chai.use(chaiChange) - -describe('Set', function() { - 'use strict' - - it('is a function', function() { - expect(Set).to.be.a('function') - }) - - context('empty set interrogation', function() { - const emptySet = new Set([]) - it('isEmpty() returns true', function() { - expect(emptySet.isEmpty()).to.be.true - }) - it('contains("x") returns false', function() { - expect(emptySet.contains('x')).to.be.false - }) - it('size() returns 0', function() { - expect(emptySet.size()).to.be.equal(0) - }) - }) - - context('non-empty set interrogation', function() { - const set = new Set([1, 2, 4, 8, 16]) - it('isEmpty() returns false', function() { - expect(set.isEmpty()).to.be.false - }) - it('contains(4) returns true', function() { - expect(set.contains(4)).to.be.true - }) - it('contains(5) returns false', function() { - expect(set.contains(5)).to.be.false - }) - it('size() returns 5', function() { - expect(set.size()).to.be.equal(5) - }) - }) - - context('dual-set interrogation', function() { - const set0 = new Set([3, 6, 9, 12, 15]) - const set1 = new Set([3, 6, 12, 24]) - it(('set0.union(set1) returns a set of 6 elements'), function() { - expect(set0.union(set1).size()).to.be.equal(6) - }) - it(('set0.union(set1) returns a set containing 15'), function() { - expect(set0.union(set1).contains(15)).to.be.true - }) - it(('set0.intersect(set1) returns a set of 3 elements'), function() { - expect(set0.intersect(set1).size()).to.be.equal(3) - }) - it(('set0.intersect(set1) returns a set containing 6'), function() { - expect(set0.intersect(set1).contains(6)).to.be.true - }) - it(('set0.intersect(set1) returns a set not containing 9'), function() { - expect(set0.intersect(set1).contains(9)).to.be.false - }) - it(('set0.difference(set1) returns a set of 2 elements'), function() { - expect(set0.intersect(set1).size()).to.be.equal(2) - }) - it(('set0.difference(set1) returns a set containing 9'), function() { - expect(set0.intersect(set1).contains(9)).to.be.true - }) - it(('set0.difference(set1) returns a set not containing 6'), function() { - expect(set0.intersect(set1).contains(6)).to.be.false - }) - it(('set1.difference(set0) returns a set of 1 element'), function() { - expect(set0.intersect(set1).size()).to.be.equal(2) - }) - it(('set1.difference(set0) returns a set containing 24'), function() { - expect(set0.intersect(set1).contains(24)).to.be.true - }) - it(('set1.difference(set0) returns a set not containing 6'), function() { - expect(set0.intersect(set1).contains(6)).to.be.false - }) - }) - -}) From b9053a70d359caf48ccb0a668cb1bf97762854eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fode=CC=81=20Diop?= Date: Thu, 18 May 2017 15:05:30 -0700 Subject: [PATCH 31/38] pass all stack tests --- spec/set.js-dev | 81 +++++++++++++++++++++++++++++++++++++++++++++++ spec/stackTest.js | 59 ++++++++++++++++++++++++++++++++++ src/stack.js | 45 ++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 spec/set.js-dev create mode 100644 spec/stackTest.js create mode 100644 src/stack.js diff --git a/spec/set.js-dev b/spec/set.js-dev new file mode 100644 index 0000000..48f2c6b --- /dev/null +++ b/spec/set.js-dev @@ -0,0 +1,81 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Set from '../src/set' + +chai.use(chaiChange) + +describe('Set', function() { + 'use strict' + + it('is a function', function() { + expect(Set).to.be.a('function') + }) + + context('empty set interrogation', function() { + const emptySet = new Set([]) + it('isEmpty() returns true', function() { + expect(emptySet.isEmpty()).to.be.true + }) + it('contains("x") returns false', function() { + expect(emptySet.contains('x')).to.be.false + }) + it('size() returns 0', function() { + expect(emptySet.size()).to.be.equal(0) + }) + }) + + context('non-empty set interrogation', function() { + const set = new Set([1, 2, 4, 8, 16]) + it('isEmpty() returns false', function() { + expect(set.isEmpty()).to.be.false + }) + it('contains(4) returns true', function() { + expect(set.contains(4)).to.be.true + }) + it('contains(5) returns false', function() { + expect(set.contains(5)).to.be.false + }) + it('size() returns 5', function() { + expect(set.size()).to.be.equal(5) + }) + }) + + context('dual-set interrogation', function() { + const set0 = new Set([3, 6, 9, 12, 15]) + const set1 = new Set([3, 6, 12, 24]) + it(('set0.union(set1) returns a set of 6 elements'), function() { + expect(set0.union(set1).size()).to.be.equal(6) + }) + it(('set0.union(set1) returns a set containing 15'), function() { + expect(set0.union(set1).contains(15)).to.be.true + }) + it(('set0.intersect(set1) returns a set of 3 elements'), function() { + expect(set0.intersect(set1).size()).to.be.equal(3) + }) + it(('set0.intersect(set1) returns a set containing 6'), function() { + expect(set0.intersect(set1).contains(6)).to.be.true + }) + it(('set0.intersect(set1) returns a set not containing 9'), function() { + expect(set0.intersect(set1).contains(9)).to.be.false + }) + it(('set0.difference(set1) returns a set of 2 elements'), function() { + expect(set0.intersect(set1).size()).to.be.equal(2) + }) + it(('set0.difference(set1) returns a set containing 9'), function() { + expect(set0.intersect(set1).contains(9)).to.be.true + }) + it(('set0.difference(set1) returns a set not containing 6'), function() { + expect(set0.intersect(set1).contains(6)).to.be.false + }) + it(('set1.difference(set0) returns a set of 1 element'), function() { + expect(set0.intersect(set1).size()).to.be.equal(2) + }) + it(('set1.difference(set0) returns a set containing 24'), function() { + expect(set0.intersect(set1).contains(24)).to.be.true + }) + it(('set1.difference(set0) returns a set not containing 6'), function() { + expect(set0.intersect(set1).contains(6)).to.be.false + }) + }) + +}) diff --git a/spec/stackTest.js b/spec/stackTest.js new file mode 100644 index 0000000..e04c0c5 --- /dev/null +++ b/spec/stackTest.js @@ -0,0 +1,59 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Stack from '../src/stack' +import Node from '../src/node' +import LinkedList from '../src/linkedlist' + +chai.use(chaiChange) + +describe('Stack', () => { + 'use strict' + const stack = new Stack() + + it('exists', () => { + expect(Stack).to.be.a( 'function' ) + }) + + context('push()', () => { + it('pushes an element to the top of the stack.', () => { + const myStack = new Stack() + expect(() => myStack.push( 'foo' )) + .to.alter(() => myStack.length(), { from: 0, to: 1 }) + }) + }) + + context('pop()', () => { + it( 'returns and removes the top element of the stack or null if empty', () => { + const newStack = new Stack() + newStack.push( 'block' ) + expect( newStack.pop() ).to.equal( 'block' ) + }) + }) + + context('peek()', () => { + it( 'returns the top element of the stack', () => { + const newStack = new Stack() + newStack.push('block1') + newStack.push('block2') + newStack.push('block3') + expect( newStack.peek() ).to.equal('block3') + }) + }) + + context('length()', () => { + it('returns the number of items in the stack', () => { + const newStack = new Stack() + newStack.push('block2') + newStack.push('block3') + expect( newStack.length() ).to.equal(2) + }) + }) + + context('isEmpty()', () => { + it('returns true is the stack is empty or false if not', () => { + const newStack = new Stack() + expect( newStack.isEmpty() ).to.equal(true) + }) + }) + +}) diff --git a/src/stack.js b/src/stack.js new file mode 100644 index 0000000..e240f42 --- /dev/null +++ b/src/stack.js @@ -0,0 +1,45 @@ +import Node from '../src/node' +import LinkedList from '../src/linkedlist' + +'use strict' + +// The classic LIFO (Last-In-First-Out) one-dimensional list. +export default class Stack { + constructor(){ + this.container = [] + this.position = 0 + + } + + length(){ + return this.position + } + + push(item){ + this.container[this.position] = item + this.position++ + } + + pop(){ + if (this.position === 0) { + return null + } else { + this.position-- + return this.container[this.position] + } + } + + peek(){ + if ( !this.position ) { + return null + } else + return this.container[this.position - 1] + } + + isEmpty() { + if ( !this.position) { + return true + } + } + +} From b0017aa7a9a235c4309f9fec74e5d826968d6b5a Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Thu, 18 May 2017 16:21:34 -0700 Subject: [PATCH 32/38] Developed, tested, and debugged Node2 and Queue2 (Pool versions of Node and Queue). --- spec/double_node.js | 75 ++++++++++++++++++++++- spec/linkedListTest.js | 2 +- spec/node2.js | 133 +++++++++++++++++++++++++++++++++++++++++ spec/queue2.js | 66 ++++++++++++++++++++ src/node2.js | 7 ++- src/priority_node.js | 2 +- src/priority_queue.js | 4 +- src/queue2.js | 42 +++++++++++++ 8 files changed, 323 insertions(+), 8 deletions(-) create mode 100644 spec/node2.js create mode 100644 spec/queue2.js create mode 100644 src/queue2.js diff --git a/spec/double_node.js b/spec/double_node.js index 26eabe3..e8576dc 100644 --- a/spec/double_node.js +++ b/spec/double_node.js @@ -71,7 +71,6 @@ describe('DoubleNode', function() { const nbNode = new DoubleNode({data: 1, next: 0}) const dxnbNode = new DoubleNode({next: ngNode}) const ngbNode = new DoubleNode({data: 0, next: dxnbNode}) - const emptyNode = new DoubleNode() const pgNode = new DoubleNode({data: 2, next: nnNode, previous: nnNode}) const pgbNode = new DoubleNode({data: 3, next: ngNode, previous: nbNode}) const pbNode = new DoubleNode({data: 4, next: ngNode, previous: "node"}) @@ -135,4 +134,78 @@ describe('DoubleNode', function() { ) }) + context('getPrevious()', function() { + const nnNode = new DoubleNode({data: 'astring'}) + const ngNode = new DoubleNode({data: 0, next: nnNode}) + const nbNode = new DoubleNode({data: 1, next: 0}) + const dxpbNode = new DoubleNode({previous: ngNode}) + const pgNode = new DoubleNode({data: 2, next: nnNode, previous: nnNode}) + const pgbNode = new DoubleNode({data: 3, next: ngNode, previous: nbNode}) + const pbNode = new DoubleNode({data: 4, next: ngNode, previous: "node"}) + it('returns the correct type, if specified', function() { + expect(pgNode.getPrevious() instanceof DoubleNode).to.be.true + }) + it('returns a DoubleNode, if an invalid one is specified', function() { + expect(pgbNode.getPrevious() instanceof DoubleNode).to.be.true + }) + it('returns the correct value, if specified', function() { + expect(pgNode.getPrevious()).to.be.deep.equal(nnNode) + }) + it( + 'returns a DoubleNode with a retrievable property, if specified', + function() { + expect(pgNode.getPrevious().getData()).to.be.equal('astring') + } + ) + it('returns null, if unspecified', function() { + expect(nnNode.getPrevious()).to.be.null + }) + it('returns null, if specified but not a DoubleNode', function() { + expect(pbNode.getPrevious()).to.be.null + }) + it('returns null, if specified but data is unspecified', function() { + expect(dxpbNode.getPrevious()).to.be.null + }) + }) + + context('setPrevious()', function() { + const nnNode = new DoubleNode({data: 0}) + const ngNode = new DoubleNode({data: 'astring', next: nnNode}) + const nbNode = new DoubleNode({data: 1, next: "nonode"}) + const pbNode = new DoubleNode({data: 2, next: ngNode, previous: "bad"}) + it('returns a DoubleNode', function() { + expect(nnNode.setPrevious(ngNode) instanceof DoubleNode).to.be.true + }) + it('returns the correct DoubleNode', function() { + expect(nnNode.setPrevious(ngNode)).to.be.deep.equal(nnNode) + }) + it( + 'returns a DoubleNode with a retrievable data property', + function() { + expect(ngNode.setPrevious(nnNode).getData()).to.be.equal('astring') + } + ) + it( + 'returns a DoubleNode with a retrievable good new previous property', + function() { + expect(nnNode.setPrevious(nnNode).getPrevious()) + .to.be.deep.equal(nnNode) + } + ) + it( + 'returns a DoubleNode with a retrievable bad new next property', + function() { + expect(nnNode.setPrevious(nbNode).getPrevious()) + .to.be.deep.equal(nbNode) + } + ) + it( + 'fails to change previous (from last value), if newPrevious is invalid', + function() { + expect(nnNode.setPrevious("badNode").getPrevious()) + .to.be.deep.equal(nbNode) + } + ) + }) + }) diff --git a/spec/linkedListTest.js b/spec/linkedListTest.js index 994efa2..f80eff5 100644 --- a/spec/linkedListTest.js +++ b/spec/linkedListTest.js @@ -5,7 +5,7 @@ import LinkedList from '../src/linkedList' chai.use(chaiChange) -describe.only('LinkedList', () => { +describe('LinkedList', () => { 'use strict' const list = new LinkedList() list.insert( {data: 'apple'} ) diff --git a/spec/node2.js b/spec/node2.js new file mode 100644 index 0000000..3497d57 --- /dev/null +++ b/spec/node2.js @@ -0,0 +1,133 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Node from '../src/node2' + +chai.use(chaiChange) + +describe('Node2', function() { + 'use strict' + + it('is a function', function() { + expect(Node).to.be.a('function') + }) + + context('getData()', function() { + const dsNode = new Node({data: 'string'}) + const dnNode = new Node({data: 0}) + const daNode = new Node({data: [1, 2]}) + const doNode = new Node({data: {'a': 1, 'b': 2}}) + const emptyNode = new Node() + const ngNode = new Node({data: 1, next: dsNode}) + const nbNode = new Node({data: 2, next: "dnNode"}) + const ngbNode = new Node({data: 3, next: nbNode}) + it('returns the correct type, if a string', function() { + expect(dsNode.getData()).to.be.a('string') + }) + it('returns the correct value, if a string', function() { + expect(dsNode.getData()).to.be.equal('string') + }) + it('returns the correct type, if a number', function() { + expect(dnNode.getData()).to.be.a('number') + }) + it('returns the correct value, if a number', function() { + expect(dnNode.getData()).to.be.equal(0) + }) + it('returns the correct type, if an array', function() { + expect(Array.isArray(daNode.getData())).to.be.true + }) + it('returns the correct value, if an array', function() { + expect(daNode.getData()).to.be.deep.equal([1, 2]) + }) + it('returns the correct type, if an object', function() { + expect(doNode.getData()).to.be.an('object') + }) + it('returns the correct value, if an object', function() { + expect(doNode.getData()).to.be.deep.equal({'a': 1, 'b': 2}) + }) + it('returns an object with a retrievable property, if an object', function() { + expect(doNode.getData().a).to.be.equal(1) + }) + it('returns the correct value, if next is specified', function() { + expect(ngNode.getData()).to.be.equal(1) + }) + it('returns the correct value, if next is a bad Node', function() { + expect(ngbNode.getData()).to.be.equal(3) + }) + it('returns undefined, if unspecified', function() { + expect(emptyNode.getData()).to.be.undefined + }) + it('returns undefined, if next is not a Node', function() { + expect(nbNode.getData()).to.be.undefined + }) + }) + + context('getNext()', function() { + const nnNode = new Node({data: 'string'}) + const ngNode = new Node({data: 0, next: nnNode}) + const nbNode = new Node({data: 1, next: 0}) + const dxnbNode = new Node({next: ngNode}) + const ngbNode = new Node({data: 0, next: dxnbNode}) + const emptyNode = new Node() + it('returns the correct type, if specified', function() { + expect(ngNode.getNext() instanceof Node).to.be.true + }) + it('returns the correct value, if specified', function() { + expect(ngNode.getNext()).to.be.deep.equal(nnNode) + }) + it( + 'returns a Node with a retrievable property, if specified', + function() { + expect(ngNode.getNext().getData()).to.be.equal('string') + } + ) + it('returns null, if unspecified', function() { + expect(nnNode.getNext()).to.be.null + }) + it('returns null, if specified but not a Node', function() { + expect(nbNode.getNext()).to.be.null + }) + it('returns null, if specified but data is unspecified', function() { + expect(dxnbNode.getNext()).to.be.null + }) + it('returns null, if data unspecified', function() { + expect(emptyNode.getNext()).to.be.null + }) + }) + + context('setNext()', function() { + const nnNode = new Node({data: 0}) + const ngNode = new Node({data: 'astring', next: nnNode}) + const nbNode = new Node({data: 1, next: "nonode"}) + it('returns a Node', function() { + expect(nnNode.setNext(ngNode) instanceof Node).to.be.true + }) + it('returns the correct Node', function() { + expect(nnNode.setNext(ngNode)).to.be.deep.equal(nnNode) + }) + it( + 'returns a Node with a retrievable data property', + function() { + expect(ngNode.setNext(nnNode).getData()).to.be.equal('astring') + } + ) + it( + 'returns a Node with a retrievable good new next property', + function() { + expect(nnNode.setNext(ngNode).getNext()).to.be.deep.equal(ngNode) + } + ) + it( + 'returns a Node with a retrievable bad new next property', + function() { + expect(nnNode.setNext(nbNode).getNext()).to.be.deep.equal(nbNode) + } + ) + it( + 'fails to change next (from last value), if newNext is invalid', + function() { + expect(nnNode.setNext("badNode").getNext()).to.be.deep.equal(nbNode) + } + ) + }) + +}) diff --git a/spec/queue2.js b/spec/queue2.js new file mode 100644 index 0000000..9046f2f --- /dev/null +++ b/spec/queue2.js @@ -0,0 +1,66 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Queue from '../src/queue2' + +chai.use(chaiChange) + +describe('Queue2', function() { + 'use strict' + + it('is a function', function() { + expect(Queue).to.be.a('function') + }) + + context('empty queue', function() { + const emptyQueue = new Queue() + it('front() returns null', function() { + expect(emptyQueue.front()).to.be.null + }) + it('back() returns null', function() { + expect(emptyQueue.back()).to.be.null + }) + it('isEmpty() returns true', function() { + expect(emptyQueue.isEmpty()).to.be.true + }) + it('length() returns 0', function() { + expect(emptyQueue.length()).to.be.equal(0) + }) + it('dequeue() returns null', function() { + expect(emptyQueue.dequeue()).to.be.null + }) + }) + + context('non-empty queue', function() { + const sQueue = new Queue() + sQueue.enqueue('bad') + sQueue.enqueue('ok') + sQueue.enqueue('good') + it('the element back() returns is “good”', function() { + expect(sQueue.back().getData()).to.be.equal('good') + }) + it('the element front() returns is “bad”', function() { + expect(sQueue.front().getData()).to.be.equal('bad') + }) + it('isEmpty() returns false', function() { + expect(sQueue.isEmpty()).to.be.false + }) + it('length() returns 3', function() { + expect(sQueue.length()).to.be.equal(3) + }) + it('the element dequeue() returns is “bad”', function() { + expect(sQueue.dequeue().getData()).to.be.equal('bad') + }) + it('the length is 2 after 1 dequeuing', function() { + expect(sQueue.length()).to.be.equal(2) + }) + it('the length is 3 after a valid enqueuing', function() { + sQueue.enqueue('excellent') + expect(sQueue.length()).to.be.equal(3) + }) + it('the length stays 3 after an invalid enqueuing', function() { + sQueue.enqueue() + expect(sQueue.length()).to.be.equal(3) + }) + }) + +}) diff --git a/src/node2.js b/src/node2.js index e5d4f2c..5855eae 100644 --- a/src/node2.js +++ b/src/node2.js @@ -8,14 +8,15 @@ export default class Node { constructor(nodeProps) { // If the argument is valid: if ( - nodeProps.data !== undefined + nodeProps !== undefined + && nodeProps.data !== undefined && ( nodeProps.next === undefined || nodeProps.next instanceof Node ) ) { this.data = nodeProps.data; - this.next = nodeProps.next; + this.next = nodeProps.next || null; } } // Returns the node’s data. @@ -28,7 +29,7 @@ export default class Node { } // Changes the next node, if specified, and returns this node. setNext(newNext) { - if (newNext instanceof PriorityNode) { + if (newNext instanceof Node) { this.next = newNext; } return this; diff --git a/src/priority_node.js b/src/priority_node.js index a7fc004..c22a6e0 100644 --- a/src/priority_node.js +++ b/src/priority_node.js @@ -20,7 +20,7 @@ export default class PriorityNode { ) { this.data = nodeProps.data; this.priority = nodeProps.priority || 0; - this.next = nodeProps.next; + this.next = nodeProps.next || null; } } // Returns the node’s data. diff --git a/src/priority_queue.js b/src/priority_queue.js index 21fe40b..37c97fe 100644 --- a/src/priority_queue.js +++ b/src/priority_queue.js @@ -39,11 +39,11 @@ export default class PriorityQueue { isEmpty() { return this.queue.length === 0; } - // Changes the next node, if specified, and returns this node. + // Returns the count of elements. length() { return this.queue.length; } - // Adds a specified element to the queue. + // Removes and returns a specified element from the queue. dequeue() { return this.queue.pop() || null; } diff --git a/src/queue2.js b/src/queue2.js new file mode 100644 index 0000000..95d451e --- /dev/null +++ b/src/queue2.js @@ -0,0 +1,42 @@ +'use strict'; +import Node from './node2'; + +/* + Class declaration for Queue and export statement making that object the + default export from this module. +*/ +export default class Queue { + constructor() { + this.queue = []; + } + // Adds a specified element to the back of the queue. + enqueue(d) { + const newNode = new Node({data: d}); + if (newNode.data !== undefined) { + this.queue.push(newNode); + } + } + /* + Removes and returns the front element from the queue. Returns null if + the queue is empty. + */ + dequeue() { + return this.queue.shift() || null; + } + // Returns the front node. + front() { + return this.queue[0] || null; + } + // Returns the back node. + back() { + return this.queue[this.queue.length - 1] || null; + } + // Returns whether the queue is empty. + isEmpty() { + return this.queue.length === 0; + } + // Returns the count of elements. + length() { + return this.queue.length; + } +} From 6e6dcda5bc462264b550fd3951baa0eaa342446f Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Thu, 18 May 2017 17:25:23 -0700 Subject: [PATCH 33/38] Created, tested, and debugged Stack2 (Pool version of Stack). --- .gitignore | 2 +- spec/stack.js-template | 22 ---------------- spec/stack2.js | 60 ++++++++++++++++++++++++++++++++++++++++++ src/stack.js-template | 5 ---- src/stack2.js | 38 ++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 28 deletions(-) delete mode 100644 spec/stack.js-template create mode 100644 spec/stack2.js delete mode 100644 src/stack.js-template create mode 100644 src/stack2.js diff --git a/.gitignore b/.gitignore index 0cd47de..07b1a3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules/ .DS_Store -notes.txt +extras/ diff --git a/spec/stack.js-template b/spec/stack.js-template deleted file mode 100644 index 743122a..0000000 --- a/spec/stack.js-template +++ /dev/null @@ -1,22 +0,0 @@ -import chai, { expect } from 'chai' -import chaiChange from 'chai-change' -import Stack from '../src/stack' - -chai.use(chaiChange) - -describe('Stack', () => { - 'use strict' - - it('exists', () => { - expect(Stack).to.be.a('function') - }) - - context('push()', () => { - it('pushes an element to the top of the stack.', () => { - const myStack = new Stack() - - expect(() => myStack.push('foo')) - .to.alter(() => myStack.length(), { from: 0, to: 1 }) - }) - }) -}) diff --git a/spec/stack2.js b/spec/stack2.js new file mode 100644 index 0000000..4d3088d --- /dev/null +++ b/spec/stack2.js @@ -0,0 +1,60 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Stack from '../src/stack2' + +chai.use(chaiChange) + +describe('Stack2', function() { + 'use strict' + + it('is a function', function() { + expect(Stack).to.be.a('function') + }) + + context('empty stack', function() { + const emptyStack = new Stack() + it('pop() returns null', function() { + expect(emptyStack.pop()).to.be.null + }) + it('peek() returns null', function() { + expect(emptyStack.peek()).to.be.null + }) + it('isEmpty() returns true', function() { + expect(emptyStack.isEmpty()).to.be.true + }) + it('length() returns 0', function() { + expect(emptyStack.length()).to.be.equal(0) + }) + }) + + context('non-empty stack', function() { + const sStack = new Stack() + sStack.push('bad') + sStack.push('ok') + sStack.push('good') + it('the element pop() returns is “good”', function() { + expect(sStack.pop().getData()).to.be.equal('good') + }) + it('the length is 2 after 1 pop', function() { + expect(sStack.length()).to.be.equal(2) + }) + it('the element peek() returns after a pop is “ok”', function() { + expect(sStack.peek().getData()).to.be.equal('ok') + }) + it('isEmpty() returns false', function() { + expect(sStack.isEmpty()).to.be.false + }) + it('length() after a pop returns 2', function() { + expect(sStack.length()).to.be.equal(2) + }) + it('the length is 3 after a valid push', function() { + sStack.push('good') + expect(sStack.length()).to.be.equal(3) + }) + it('the length stays 3 after an invalid push', function() { + sStack.push() + expect(sStack.length()).to.be.equal(3) + }) + }) + +}) diff --git a/src/stack.js-template b/src/stack.js-template deleted file mode 100644 index dcd1d13..0000000 --- a/src/stack.js-template +++ /dev/null @@ -1,5 +0,0 @@ -'use strict' - -export default class Stack { - // your code here -} diff --git a/src/stack2.js b/src/stack2.js new file mode 100644 index 0000000..0ffb914 --- /dev/null +++ b/src/stack2.js @@ -0,0 +1,38 @@ +'use strict'; +import Node from './node2'; + +/* + Class declaration for Stack and export statement making that object the + default export from this module. +*/ +export default class Stack { + constructor() { + this.stack = []; + } + // Adds a specified element to the top of the stack. + push(d) { + const newNode = new Node({data: d}); + if (newNode.data !== undefined) { + this.stack.push(newNode); + } + } + /* + Removes and returns the top element from the stack. Returns null if + the stack is empty. + */ + pop() { + return this.stack.pop() || null; + } + // Returns the top node. + peek() { + return this.stack[this.stack.length - 1] || null; + } + // Returns whether the stack is empty. + isEmpty() { + return this.stack.length === 0; + } + // Returns the count of elements. + length() { + return this.stack.length; + } +} From 8c5f115569a125cd73f92ad38dde6fe9fa5d1751 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Thu, 18 May 2017 17:39:20 -0700 Subject: [PATCH 34/38] Created, tested, and debugged LinkedList2 (Pool version of LinkedList). --- spec/linked_list2.js | 118 ++++++++++++++++++++++++++++++++++++++ src/linked_list2.js | 133 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 spec/linked_list2.js create mode 100644 src/linked_list2.js diff --git a/spec/linked_list2.js b/spec/linked_list2.js new file mode 100644 index 0000000..7b1d9d9 --- /dev/null +++ b/spec/linked_list2.js @@ -0,0 +1,118 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import LinkedList from '../src/linked_list2' + +chai.use(chaiChange) + +describe('LinkedList', function() { + 'use strict' + + it('is a function', function() { + expect(LinkedList).to.be.a('function') + }) + + context('empty list interrogation', function() { + const emptyList = new LinkedList() + it('getHeadNode() returns null', function() { + expect(emptyList.getHeadNode()).to.be.null + }) + it('getTailNode() returns null', function() { + expect(emptyList.getTailNode()).to.be.null + }) + it('isEmpty() returns true', function() { + expect(emptyList.isEmpty()).to.be.true + }) + it('size() returns 0', function() { + expect(emptyList.size()).to.be.equal(0) + }) + it('contains("x") returns false', function() { + expect(emptyList.contains('x')).to.be.false + }) + it('find("x") returns -1', function() { + expect(emptyList.find('x')).to.be.equal(-1) + }) + }) + + context('non-empty list interrogation', function() { + const lList = new LinkedList() + lList.insert('bad') + lList.insert('ok') + lList.insert('good') + it('the element getHeadNode() returns has data “bad”', function() { + expect(lList.getHeadNode().getData()).to.be.equal('bad') + }) + it('the element getTailNode() returns has data “good”', function() { + expect(lList.getTailNode().getData()).to.be.equal('good') + }) + it('contains("ok") returns true', function() { + expect(lList.contains('ok')).to.be.true + }) + it('contains("mediocre") returns false', function() { + expect(lList.contains('mediocre')).to.be.false + }) + it('find("ok") returns a node with data “ok”', function() { + expect(lList.find('ok').getData()).to.be.equal('ok') + }) + it('find("mediocre") returns -1', function() { + expect(lList.find('mediocre')).to.be.equal(-1) + }) + it('isEmpty() returns false', function() { + expect(lList.isEmpty()).to.be.false + }) + it('size() returns 3', function() { + expect(lList.size()).to.be.equal(3) + }) + }) + + context('list manipulation', function() { + const lList = new LinkedList() + lList.insert('bad') + lList.insert('ok') + lList.insert('good') + lList.insertFirst('horrible') + it(('insertFirst() changes the head (first) element'), function() { + expect(lList.getHeadNode().getData()).to.be.equal('horrible') + }) + it('insertFirst() does not change the tail (last) element', function() { + expect(lList.getTailNode().getData()).to.be.equal('good') + }) + it('no element has data “mediocre”', function() { + expect(lList.contains('mediocre')).to.be.false + }) + it('insertBefore() inserts an element where specified', function() { + lList.insertBefore('ok', 'mediocre') + expect(lList.contains('mediocre')).to.be.true + }) + it('insertBefore() inserts nothing if no target exists', function() { + const lSizeOld = lList.size(); + lList.insertBefore('stupendous', 'superb') + expect(lList.size()).to.be.equal(lSizeOld) + }) + it('insertAfter() not after the last element does not change it', function() { + lList.insertAfter('horrible', 'lousy') + expect(lList.getTailNode().getData()).to.be.equal('good') + }) + it('insertAfter() after the last element changes it', function() { + lList.insertAfter('good', 'excellent') + expect(lList.getTailNode().getData()).to.be.equal('excellent') + }) + it('insertAfter() inserts nothing if no target exists', function() { + const lSizeOld = lList.size(); + lList.insertAfter('superb', 'stupendous') + expect(lList.size()).to.be.equal(lSizeOld) + }) + it('remove() changes the tail (last) element', function() { + lList.remove() + expect(lList.getTailNode().getData()).to.be.equal('good') + }) + it('removeFirst() changes the head (first) element', function() { + lList.removeFirst() + expect(lList.getHeadNode().getData()).to.be.equal('lousy') + }) + it('clear() makes the list’s size 0', function() { + lList.clear() + expect(lList.size()).to.be.equal(0) + }) + }) + +}) diff --git a/src/linked_list2.js b/src/linked_list2.js new file mode 100644 index 0000000..3c833e0 --- /dev/null +++ b/src/linked_list2.js @@ -0,0 +1,133 @@ +'use strict'; +import Node from './node2'; + +/* + Class declaration for LinkedList and export statement making that + object the default export from this module. +*/ +export default class LinkedList { + constructor() { + this.list = []; + } + + // UTILITY METHODS + + /* + Returns the index of the first element with a data value identical to + the specified one, or -1 if no such element exists. “First” = having the + smallest index. The array contains the nodes, with the head (first) node + at index 0. + */ + firstMatchIndex(data) { + let fmIndex = 0; + while (fmIndex < this.list.length) { + if (this.list[fmIndex].getData() === data) { + return fmIndex; + } + else { + fmIndex++; + } + } + return -1; + } + + // INTERROGATION METHODS + + // Returns the head (first) node. + getHeadNode() { + return this.list[0] || null; + } + + // Returns the tail (last) node. + getTailNode() { + return this.list[this.list.length - 1] || null; + } + + /* + Returns whether the list contains an element with the specified data + value. + */ + contains(data) { + return this.firstMatchIndex(data) > -1; + } + + /* + Returns the first node containing an element with the specified data + value. + */ + find(data) { + return this.list[this.firstMatchIndex(data)] || -1; + } + + // Returns whether the list is empty. + isEmpty() { + return this.list.length === 0; + } + + // Returns the length of the list. + size() { + return this.list.length; + } + + // MANIPULATION METHODS + + // Adds a specified element at the tail (as the last element). + insert(d) { + if (d !== undefined) { + const newNode = new Node({data: d}); + this.list.push(newNode); + } + } + + // Adds a specified element at the head (as the first element). + insertFirst(d) { + if (d !== undefined) { + const newNode = new Node({data: d}); + this.list.unshift(newNode); + } + } + + /* + Adds a specified element before the first element with a specified + data value. + */ + insertBefore(d, n) { + if (d !== undefined && n !== undefined) { + const fmIndex = this.firstMatchIndex(d); + if (fmIndex > -1) { + const newNode = new Node({data: n}); + this.list.splice(fmIndex, 0, newNode); + } + } + } + + /* + Adds a specified element after the first element with a specified + data value. + */ + insertAfter(d, n) { + if (d !== undefined && n !== undefined) { + const fmIndex = this.firstMatchIndex(d); + if (fmIndex > -1) { + const newNode = new Node({data: n}); + this.list.splice(fmIndex + 1, 0, newNode); + } + } + } + + // Deletes the last (tail) element. + remove() { + this.list.pop(); + } + + // Deletes the first (head) element. + removeFirst() { + this.list.shift(); + } + + // Deletes all elements. + clear() { + this.list.splice(0); + } + +} From e3d2fb80a68ace834c21021a7bbf5ff1c4247ad2 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Fri, 19 May 2017 10:29:05 -0700 Subject: [PATCH 35/38] Cleanup and parking of linked_list3. --- README.md | 2 +- spec/{linkedListTest.js => linked_list1.js} | 6 +++--- spec/linked_list2.js | 2 +- spec/{nodeTest.js => node1.js} | 4 ++-- spec/{queue2.js => queue.js} | 4 ++-- src/{linkedList.js => linked_list1.js} | 2 +- src/{node.js => node1.js} | 0 src/{queue2.js => queue.js} | 0 8 files changed, 10 insertions(+), 10 deletions(-) rename spec/{linkedListTest.js => linked_list1.js} (96%) rename spec/{nodeTest.js => node1.js} (95%) rename spec/{queue2.js => queue.js} (96%) rename src/{linkedList.js => linked_list1.js} (99%) rename src/{node.js => node1.js} (100%) rename src/{queue2.js => queue.js} (100%) diff --git a/README.md b/README.md index e0ba10b..ed13bf4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Tests and implementations for common data structures. See the full list in the [ Project Goal: [Core Data Structures - Basic](http://jsdev.learnersguild.org/goals/156-Core_Data_Structures-Basic.html) -Base repository for the [Core Data Structures](Core Data Structures--Basic) goal. +Base repository: [Core Data Structures--Basic](https://github.com/diop/core-data-structures) Team Name: ten-seal diff --git a/spec/linkedListTest.js b/spec/linked_list1.js similarity index 96% rename from spec/linkedListTest.js rename to spec/linked_list1.js index f80eff5..59ac927 100644 --- a/spec/linkedListTest.js +++ b/spec/linked_list1.js @@ -1,11 +1,11 @@ import chai, { expect } from 'chai' import chaiChange from 'chai-change' -import Node from '../src/node' -import LinkedList from '../src/linkedList' +import Node from '../src/node1' +import LinkedList from '../src/linked_list1' chai.use(chaiChange) -describe('LinkedList', () => { +describe('LinkedList1', () => { 'use strict' const list = new LinkedList() list.insert( {data: 'apple'} ) diff --git a/spec/linked_list2.js b/spec/linked_list2.js index 7b1d9d9..e9810a0 100644 --- a/spec/linked_list2.js +++ b/spec/linked_list2.js @@ -4,7 +4,7 @@ import LinkedList from '../src/linked_list2' chai.use(chaiChange) -describe('LinkedList', function() { +describe('LinkedList2', function() { 'use strict' it('is a function', function() { diff --git a/spec/nodeTest.js b/spec/node1.js similarity index 95% rename from spec/nodeTest.js rename to spec/node1.js index d39923b..8c839ef 100644 --- a/spec/nodeTest.js +++ b/spec/node1.js @@ -1,11 +1,11 @@ import chai, { expect } from 'chai' import chaiChange from 'chai-change' -import Node from '../src/node' +import Node from '../src/node1' chai.use(chaiChange) -describe('Node', () => { +describe('Node1', () => { 'use strict' it('is a function', () => { diff --git a/spec/queue2.js b/spec/queue.js similarity index 96% rename from spec/queue2.js rename to spec/queue.js index 9046f2f..0dc4581 100644 --- a/spec/queue2.js +++ b/spec/queue.js @@ -1,10 +1,10 @@ import chai, { expect } from 'chai' import chaiChange from 'chai-change' -import Queue from '../src/queue2' +import Queue from '../src/queue' chai.use(chaiChange) -describe('Queue2', function() { +describe('Queue', function() { 'use strict' it('is a function', function() { diff --git a/src/linkedList.js b/src/linked_list1.js similarity index 99% rename from src/linkedList.js rename to src/linked_list1.js index 5d18e91..26a63b2 100644 --- a/src/linkedList.js +++ b/src/linked_list1.js @@ -1,4 +1,4 @@ -import Node from '../src/node' +import Node from '../src/node1' 'use strict' diff --git a/src/node.js b/src/node1.js similarity index 100% rename from src/node.js rename to src/node1.js diff --git a/src/queue2.js b/src/queue.js similarity index 100% rename from src/queue2.js rename to src/queue.js From 469b96253f2d7c78f6e5d9cb0087cdb4f44ce99b Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Fri, 19 May 2017 10:38:33 -0700 Subject: [PATCH 36/38] Made file names consistent, merged stack1, finished readme file. --- README.md | 4 ---- spec/{stackTest.js => stack1.js} | 7 +++---- src/{stack.js => stack1.js} | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) rename spec/{stackTest.js => stack1.js} (91%) rename src/{stack.js => stack1.js} (89%) diff --git a/README.md b/README.md index ed13bf4..3c3e992 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,3 @@ Project Members: eslint --init 5. Edit .eslintrc.json in your home directory to customize. - -## Usage and Examples - -_...and this_ diff --git a/spec/stackTest.js b/spec/stack1.js similarity index 91% rename from spec/stackTest.js rename to spec/stack1.js index e04c0c5..12d77b2 100644 --- a/spec/stackTest.js +++ b/spec/stack1.js @@ -1,12 +1,11 @@ import chai, { expect } from 'chai' import chaiChange from 'chai-change' -import Stack from '../src/stack' -import Node from '../src/node' -import LinkedList from '../src/linkedlist' +import Stack from '../src/stack1' +import Node from '../src/node1' chai.use(chaiChange) -describe('Stack', () => { +describe('Stack1', () => { 'use strict' const stack = new Stack() diff --git a/src/stack.js b/src/stack1.js similarity index 89% rename from src/stack.js rename to src/stack1.js index e240f42..7434014 100644 --- a/src/stack.js +++ b/src/stack1.js @@ -1,5 +1,5 @@ -import Node from '../src/node' -import LinkedList from '../src/linkedlist' +import Node from '../src/node1' +import LinkedList from '../src/linked_list1' 'use strict' From 1eb54bc3d8ec188a93d0c38ad8b5adaf4437e7e8 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Fri, 19 May 2017 11:04:42 -0700 Subject: [PATCH 37/38] Parked stack1 for further work. Made linting corrections. --- spec/{stack2.js => stack.js} | 4 +- spec/stack1.js | 58 ----------- src/double_node.js | 2 +- src/linked_list1.js | 189 +++++++++++++++++------------------ src/node1.js | 16 +-- src/node2.js | 2 +- src/power_set.js | 8 +- src/priority_node.js | 2 +- src/{stack2.js => stack.js} | 0 src/stack1.js | 45 --------- 10 files changed, 111 insertions(+), 215 deletions(-) rename spec/{stack2.js => stack.js} (96%) delete mode 100644 spec/stack1.js rename src/{stack2.js => stack.js} (100%) delete mode 100644 src/stack1.js diff --git a/spec/stack2.js b/spec/stack.js similarity index 96% rename from spec/stack2.js rename to spec/stack.js index 4d3088d..dfd9994 100644 --- a/spec/stack2.js +++ b/spec/stack.js @@ -1,10 +1,10 @@ import chai, { expect } from 'chai' import chaiChange from 'chai-change' -import Stack from '../src/stack2' +import Stack from '../src/stack' chai.use(chaiChange) -describe('Stack2', function() { +describe('Stack', function() { 'use strict' it('is a function', function() { diff --git a/spec/stack1.js b/spec/stack1.js deleted file mode 100644 index 12d77b2..0000000 --- a/spec/stack1.js +++ /dev/null @@ -1,58 +0,0 @@ -import chai, { expect } from 'chai' -import chaiChange from 'chai-change' -import Stack from '../src/stack1' -import Node from '../src/node1' - -chai.use(chaiChange) - -describe('Stack1', () => { - 'use strict' - const stack = new Stack() - - it('exists', () => { - expect(Stack).to.be.a( 'function' ) - }) - - context('push()', () => { - it('pushes an element to the top of the stack.', () => { - const myStack = new Stack() - expect(() => myStack.push( 'foo' )) - .to.alter(() => myStack.length(), { from: 0, to: 1 }) - }) - }) - - context('pop()', () => { - it( 'returns and removes the top element of the stack or null if empty', () => { - const newStack = new Stack() - newStack.push( 'block' ) - expect( newStack.pop() ).to.equal( 'block' ) - }) - }) - - context('peek()', () => { - it( 'returns the top element of the stack', () => { - const newStack = new Stack() - newStack.push('block1') - newStack.push('block2') - newStack.push('block3') - expect( newStack.peek() ).to.equal('block3') - }) - }) - - context('length()', () => { - it('returns the number of items in the stack', () => { - const newStack = new Stack() - newStack.push('block2') - newStack.push('block3') - expect( newStack.length() ).to.equal(2) - }) - }) - - context('isEmpty()', () => { - it('returns true is the stack is empty or false if not', () => { - const newStack = new Stack() - expect( newStack.isEmpty() ).to.equal(true) - }) - }) - -}) diff --git a/src/double_node.js b/src/double_node.js index 4139aba..8a98fb8 100644 --- a/src/double_node.js +++ b/src/double_node.js @@ -1,4 +1,4 @@ -'use strict' +'use strict'; /* Class declaration for DoubleNode and export statement making that diff --git a/src/linked_list1.js b/src/linked_list1.js index 26a63b2..90a73ef 100644 --- a/src/linked_list1.js +++ b/src/linked_list1.js @@ -1,168 +1,167 @@ -import Node from '../src/node1' +import Node from '../src/node1'; -'use strict' +'use strict'; // A list of nodes that link to each other, like a daisy-chain. export default class LinkedList { - constructor( data ) { - this.head = null - this.tail = null - this.length = 0 + constructor() { + this.head = null; + this.tail = null; + this.length = 0; } getHeadNode(){ - return this.head + return this.head; } getTailNode() { - return this.tail + return this.tail; } contains( fruit ){ - let currentNode = this.head + let currentNode = this.head; while( currentNode ) { - if ( currentNode.data === fruit) { - return true - } - if ( currentNode = this.tail ) { - return false - } else { - currentNode = currentNode.next - } + if ( currentNode.data === fruit) { + return true; } + if ( currentNode === this.tail ) { + return false; + } else { + currentNode = currentNode.next; + } + } } find( fruit ){ - let currentNode = this.head + let currentNode = this.head; while ( currentNode.next !== null ) { - if ( currentNode.data === fruit ){ - return currentNode - } - currentNode = currentNode.next + if ( currentNode.data === fruit ){ + return currentNode; + } + currentNode = currentNode.next; } - return -1 + return -1; } insert( fruit ){ - let newNode = new Node( fruit ) - let currentNode = this.head + let newNode = new Node( fruit ); + let currentNode = this.head; if ( !currentNode && this.length === 0 ) { - this.head = newNode - this.tail = newNode + this.head = newNode; + this.tail = newNode; } else { - this.tail.next = newNode - this.tail = newNode + this.tail.next = newNode; + this.tail = newNode; } - this.length++ + this.length++; } insertFirst(fruit){ - let newNode = new Node( fruit ) - let currentNode = this.head + let newNode = new Node( fruit ); + let currentNode = this.head; if ( !currentNode ) { - this.head = newNode - this.tail = newNode + this.head = newNode; + this.tail = newNode; } else { - newNode.next = this.head - this.head = newNode + newNode.next = this.head; + this.head = newNode; } - currentNode = currentNode.next - this.length++ + currentNode = currentNode.next; + this.length++; } insertBefore( target, data){ - let newNode = new Node( data ) - let currentNode = this.head + let newNode = new Node( data ); + let currentNode = this.head; if ( this.length == 1 ) { - newNode.next = this.head - this.head = newNode + newNode.next = this.head; + this.head = newNode; } while ( currentNode ) { - if ( currentNode.data == target) { - newNode.next = currentNode - this.head = newNode - return - } - if ( currentNode.next.data == target ) { - newNode.next = currentNode.next - currentNode.next = newNode - return - } - if ( currentNode == this.tail ){ - return 'non-existent node in this list.' - } - else { - currentNode = currentNode.next - } + if ( currentNode.data == target) { + newNode.next = currentNode; + this.head = newNode; + return; + } + if ( currentNode.next.data == target ) { + newNode.next = currentNode.next; + currentNode.next = newNode; + return; + } + if ( currentNode == this.tail ){ + return 'non-existent node in this list.'; + } + else { + currentNode = currentNode.next; + } } - this.length++ + this.length++; } insertAfter( target, data){ - let newNode = new Node( data ) - let currentNode = this.head + let newNode = new Node( data ); + let currentNode = this.head; if ( this.length == 1 ) { - currentNode.next = newNode + currentNode.next = newNode; } while ( currentNode ) { - if ( currentNode.data == target) { - newNode = currentNode.next - currentNode.next = newNode - return - } - if ( currentNode == this.tail ){ - return 'No fruit' - } - else { - currentNode = currentNode.next - } + if ( currentNode.data == target) { + newNode = currentNode.next; + currentNode.next = newNode; + return; + } + if ( currentNode == this.tail ){ + return 'No fruit'; + } + else { + currentNode = currentNode.next; + } } - this.length++ + this.length++; } remove() { - let currentNode = this.head - while( currentNode.next ) { - if( currentNode.next === this.tail){ - currentNode = this.tail - currentNode.next = null - } - this.length - return + let currentNode = this.head; + while( currentNode.next ) { + if( currentNode.next === this.tail){ + currentNode = this.tail; + currentNode.next = null; } - currentNode = currentNode + this.length; + return; + } } removeFirst() { - let currentNode = this.head - this.head = currentNode.next - this.length - return + let currentNode = this.head; + this.head = currentNode.next; + this.length; + return; } isEmpty() { - if ( this.head == null) { - return true - } - return false + if ( this.head == null) { + return true; + } + return false; } size() { - return this.length + return this.length; } clear() { - this.tail = null - this.head = this.tail - this.length = 0 + this.tail = null; + this.head = this.tail; + this.length = 0; } } diff --git a/src/node1.js b/src/node1.js index 0edc003..950e42f 100644 --- a/src/node1.js +++ b/src/node1.js @@ -1,28 +1,28 @@ -'use strict' +'use strict'; // A very basic data structure that can contain some value and a reference to another node. export default class Node { constructor( nodeData ) { - this.data = nodeData.data - this.next = null + this.data = nodeData.data; + this.next = null; } // returns the data ("apple") of the node getData() { - return this.data + return this.data; } // changes the reference to the next node and returns the original node setNext( element ) { - this.next = element - return this + this.next = element; + return this; } // returns the next node, or null if no next node getNext() { if ( this.next ) { - return this.next + return this.next; } - return null + return null; } } diff --git a/src/node2.js b/src/node2.js index 5855eae..99e8556 100644 --- a/src/node2.js +++ b/src/node2.js @@ -1,4 +1,4 @@ -'use strict' +'use strict'; /* Class declaration for Node and export statement making that diff --git a/src/power_set.js b/src/power_set.js index 3774b87..dd89a0e 100644 --- a/src/power_set.js +++ b/src/power_set.js @@ -31,7 +31,7 @@ export default class PowerSet { // Returns the union of this and another powerSet. union(otherPowerSet) { const newPowerSet = new PowerSet(this.pSet); - const addToThis = function(element, key, sourceSet) { + const addToThis = function(element) { this.add(element); }; otherPowerSet.pSet.forEach(addToThis, newPowerSet.pSet); @@ -41,7 +41,7 @@ export default class PowerSet { // Returns the intersection of this and another powerSet. intersect(otherPowerSet) { const newPowerSet = new PowerSet(); - const addToThis = function(element, key, thisSet) { + const addToThis = function(element) { if (otherPowerSet.contains(element)) { this.add(element); } @@ -53,7 +53,7 @@ export default class PowerSet { // Returns the difference of this from another powerSet. difference(otherPowerSet) { const newPowerSet = new PowerSet(); - const addToThis = function(element, key, thisSet) { + const addToThis = function(element) { if (! otherPowerSet.contains(element)) { this.add(element); } @@ -64,7 +64,7 @@ export default class PowerSet { // Returns whether this is a subset of another powerSet. isSubset(otherPowerSet) { - for (element of this.pSet) { + for (let element of this.pSet) { if (! otherPowerSet.contains(element)) { return false; } diff --git a/src/priority_node.js b/src/priority_node.js index c22a6e0..41fa77e 100644 --- a/src/priority_node.js +++ b/src/priority_node.js @@ -1,4 +1,4 @@ -'use strict' +'use strict'; /* Class declaration for PriorityNode and export statement making that diff --git a/src/stack2.js b/src/stack.js similarity index 100% rename from src/stack2.js rename to src/stack.js diff --git a/src/stack1.js b/src/stack1.js deleted file mode 100644 index 7434014..0000000 --- a/src/stack1.js +++ /dev/null @@ -1,45 +0,0 @@ -import Node from '../src/node1' -import LinkedList from '../src/linked_list1' - -'use strict' - -// The classic LIFO (Last-In-First-Out) one-dimensional list. -export default class Stack { - constructor(){ - this.container = [] - this.position = 0 - - } - - length(){ - return this.position - } - - push(item){ - this.container[this.position] = item - this.position++ - } - - pop(){ - if (this.position === 0) { - return null - } else { - this.position-- - return this.container[this.position] - } - } - - peek(){ - if ( !this.position ) { - return null - } else - return this.container[this.position - 1] - } - - isEmpty() { - if ( !this.position) { - return true - } - } - -} From 8f487e2024db5c08d95156bbe7b6fc5889315df9 Mon Sep 17 00:00:00 2001 From: Jonathan Pool Date: Fri, 19 May 2017 11:24:54 -0700 Subject: [PATCH 38/38] Added explanatory comments to README file. --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 3c3e992..46c8a94 100644 --- a/README.md +++ b/README.md @@ -37,3 +37,13 @@ Project Members: eslint --init 5. Edit .eslintrc.json in your home directory to customize. + +## Comments + +Each structure implementation in this repository relies on one of two features: (1) the next property of Node objects or the next and previous properties of DoubleNode objects, or (2) the properties and methods of JavaScript Array or Set objects. + +Some data structures are implemented twice in this repository. Where this is the case, they are named with “1” and “2” suffixes. A structure implementation with “1” relies on Node or DoubleNode properties; one with “2” relies on Array or Set properties and methods. + +The Node object has two implementations differing in internal validation, each with its own tests. + +The Set implementation is named “PowerSet” so as to avoid any confusion with JavaScript Set objects.