From 6cc3efcb1489b6c3f33691795abbeb39583dd29a Mon Sep 17 00:00:00 2001 From: Tanner Welsh Date: Sat, 31 Dec 2016 11:09:11 -0500 Subject: [PATCH 01/17] Skeleton for tests & implementations using babel, mocha, chai --- .babelrc | 3 +++ lib/stack.js | 13 +++++++++++++ package.json | 18 ++++++++++++++++++ spec/stack.js | 22 ++++++++++++++++++++++ src/stack.js | 5 +++++ 5 files changed, 61 insertions(+) create mode 100644 .babelrc create mode 100644 lib/stack.js create mode 100644 package.json create mode 100644 spec/stack.js create mode 100644 src/stack.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..2f01e1d --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["env"] +} \ No newline at end of file diff --git a/lib/stack.js b/lib/stack.js new file mode 100644 index 0000000..9de25fb --- /dev/null +++ b/lib/stack.js @@ -0,0 +1,13 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Stack = function Stack() { + _classCallCheck(this, Stack); +}; + +exports.default = Stack; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..d47a351 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "core-data-structures", + "description": "Tests and implementations for common data structures.", + "private": false, + "version": "0.0.0", + "devDependencies": { + "babel-cli": "^6.18.0", + "babel-preset-env": "^1.1.4", + "babel-register": "^6.18.0", + "chai": "~1.8.0", + "chai-change": "^2.1.2", + "mocha": "2.0.1" + }, + "scripts": { + "build": "babel src -d lib", + "test": "mocha --compilers js:babel-register ./spec/*.js" + } +} diff --git a/spec/stack.js b/spec/stack.js new file mode 100644 index 0000000..743122a --- /dev/null +++ b/spec/stack.js @@ -0,0 +1,22 @@ +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/src/stack.js b/src/stack.js new file mode 100644 index 0000000..dcd1d13 --- /dev/null +++ b/src/stack.js @@ -0,0 +1,5 @@ +'use strict' + +export default class Stack { + // your code here +} From bf34f68c6a710d54811683e314f6eb1dd9f5c181 Mon Sep 17 00:00:00 2001 From: Tanner Welsh Date: Sat, 31 Dec 2016 11:18:56 -0500 Subject: [PATCH 02/17] Fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fd4e02..c6fff0d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Tests and implementations for common data structures. -Base repository for the [Core Data Structures](https://github.com/GuildCrafts/web-development-js/issues/127) goal. +Base repository for the [Core Data Structures](https://github.com/GuildCrafts/web-development-js/issues/128) goal. ## Installation and Setup From 212bed15fca06be26b4c7f6f524e83ed8fb65e35 Mon Sep 17 00:00:00 2001 From: Najee Amaranth Date: Tue, 17 Jan 2017 10:45:05 -0800 Subject: [PATCH 03/17] Update README.md --- README.md | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 256 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c6fff0d..4a4b29a 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,260 @@ -# Core Data Structures +## Description -Tests and implementations for common data structures. +_Provide a brief, high-level overview of what the final product (artifact) of this goal is. Include any relevant resources or dependencies here._ -Base repository for the [Core Data Structures](https://github.com/GuildCrafts/web-development-js/issues/128) goal. +Write tests and implementations for common data structures. -## Installation and Setup +Fork the [core-data-structures][core-data-structures] repository and use the fork as your project artifact. -## Usage and Examples +Use the list below as a reference for each data structure's interface. + +### Stack + +The classic LIFO (Last-In-First-Out) one-dimensional list. + +From [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) [edited]: + +> An abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed. The order in which elements come off a stack gives rise to its alternative name, LIFO (for last in, first out). Additionally, a peek operation may give access to the top without modifying the stack. + +```javascript +const stack = new Stack() +stack.push("foo") // push an element (the string "foo") to the top of the stack. +stack.pop() // returns and removes the top element in the stack or null if the stack is empty. +stack.peek() // returns the top element in the stack or null if the stack is empty. +stack.isEmpty() // returns true if the stack is empty or false if not. +stack.length() // returns the number of elements in the stack. +``` + +### Queue + +The classic FIFO (First-In-First-Out) one-dimensional list. + +From [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) [edited]: + +> A particular kind of abstract data type or collection in which the entities in the collection are kept in order and the principal (or only) operations on the collection are the addition of entities to the rear terminal position, known as enqueue, and removal of entities from the front terminal position, known as dequeue. + +```javascript +const queue = new Queue() +queue.enqueue("foo") // adds an element (the string "foo") to the back of the queue. +queue.dequeue() // returns and removes the front element in the queue or null if the queue is empty. +queue.front() // returns the front element in queue or null if the queue is empty. +queue.back() // returns the back element in the queue or null if the queue is empty. +queue.isEmpty() // returns true if the queue is empty or false if not. +queue.length() // returns the number of elements in the queue +``` + +### Priority Queue + +Like a queue, but with _priorities_. + +From [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue) [edited]: + +> An abstract data type which is like a regular queue or stack data structure, but where additionally each element has a "priority" associated with it. An element with high priority is served before an element with low priority. If two elements have the same priority, they are served according to their order in the queue. + +```javascript +const pQueue = new PriorityQueue() +pQueue.enqueue("pizza", 100) // adds an element with priority (number) to the back of the queue. +pQueue.front() // returns the front element (highest priority) in the queue or null if the queue is empty. +pQueue.back() // returns the back element (lowest priority) in the queue or null if the queue is empty. +pQueue.dequeue() // returns and removes the front element (highest priority) in the queue or null if the queue is empty. +pQueue.isEmpty() // returns true if the queue is empty or false if not. +pQueue.length() // returns the number of elements in the queue. +``` + +### Set + +Collection of things, without repetition. + +From [Wikipedia](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) [edited]: + +> An abstract data type that can store certain values, without any particular order, and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set. + +```javascript +const set = new Set(['A', 'B', 'C']) +const otherSet = new Set(['B', 'C', 'E']) +set.add('D') // adds an element to the set. +set.isEmpty() // returns true if the set is empty or false if not. +set.contains('B') // returns true the set contains the element or false if not. +set.remove('C') // removes an element (if it exists) from the set. +set.forEach(elem => console.log(elem)) // takes a callback function and passes it each element in sequence. +set.size() // returns the number of elements in the set. +set.union(otherSet) // unions the set with another set and returns the resulting set. +set.intersect(otherSet) // intersects the set with another set and returns the resulting set. +set.difference(otherSet) // returns a set that contains the elements found in the set but not in otherSet. +set.isSubset(otherSet) // returns true if the set is a subset of otherSet or false if not. +set.clone() // returns a cloned set. +``` + +### Linked List + +A list of nodes that link to each other, like a daisy-chain. + +From [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) [edited]: + +> A linear collection of data elements, called nodes, each pointing to the next node by means of a pointer. It is a data structure consisting of a group of nodes which together represent a sequence. + +Specifically, the following is a _singly-linked_ list (as opposed to the _doubly-linked_ list below). + +```javascript +const linkedList = new LinkedList() +linkedList.getHeadNode() // Returns the first node in the list +linkedList.getTailNode() // Returns the last node in the list +linkedList.contains("bananas") // Determines whether or not the list contains the provided data +linkedList.find("bananas") // Returns the first node containing the provided data, or -1 if not found +linkedList.insert("bananas") // Inserts a node (with the provided data) to the tail of the list +linkedList.insertFirst("bananas") // Inserts a node (with the provided data) to the head of the list +linkedList.insertBefore("bananas", "apples") // Inserts a node (with data "apples") before the first node containing "bananas" +linkedList.insertAfter("apples", "bananas") // Inserts a node (with data "bananas") after the first node containing "apples" +linkedList.remove() // Removes the tail node from the list +linkedList.removeFirst() // Removes the head node from the list +linkedList.isEmpty() // Determines if the list is empty or not +linkedList.size() // Returns the size of the list (number of nodes) +linkedList.clear() // Clears the list of all nodes/data + +const node = linkedList.find("apple") +node.data() // Returns the data ("apple") of the node +node.next() // Returns the next node, or null if no next node +``` + +### Doubly-Linked List + +The interface for the Doubly-Linked List is the same as the Linked List above, _except_ that the nodes also have a `.prev()` method, pointing to the previous node in the sequence, or null if it is the head of the list. + +From [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list) [edited]: + +> A linked data structure that consists of a set of sequentially linked records called nodes. Each node contains two fields, called _links_, that are references to the previous and to the next node in the sequence of nodes. + +### Hash Table + +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. + +```javascript +const ht = new HashTable() +ht.put("name", "Zanzibar") // adds a key-value pair to the hash table. +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 + +Maps keys to values, like a dictionary or a phone book. Or an object in JavaScript... + +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('inOrder', (val) => console.log(val)) // traverse the tree in the defined order (either 'preOrder', 'inOrder', or 'postOrder') and apply function on each node's value. +bst.count() // return the number of nodes in the tree. +``` + +### 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' , 3) // adds a direction from 'v1' to 'v2' with a weight (number). +diGraph.hasDirection('v1', 'v2') // returns true if there's a direction from 'v1' to 'v2'. +diGraph.getDirectionWeight('v1', 'v2') // returns direction weight between v1 & v2 or null if no direction exists. +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.findShortestPath('v1', 'v2') // returns an array of all the shortest paths between two vertices based on the sum of weights. +diGraph.removeDirection('v1', 'v2') // removes an existing direction between 'v1' and 'v2'. +diGraph.getSeparatedVertices() // returns an array of all the vertices that are separated from the graph. +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 below was shamelessly borrowed from Wikipedia and these libraries: + +- [datastructures-js](https://github.com/eyas-ranjous/datastructures-js) +- [singly-linked-list](https://www.npmjs.com/package/singly-linked-list) + +## Context + +_Why is this goal important? How is it useful? What questions will it raise?_ + +If you spend most of your time programming in high-level languages, you may not realize how often you use data structures or how they are built. Sometimes it's useful to peek under the hood and see how the engine works. + +The nice thing is, most data structures are **actually quite simple** when you get down to it. They have straight-forward, relatively small interfaces. + +In a larger sense, being more familiar with data structures is helpful for you ability to think about data more abstractly, and to design better software. + +## Specifications + +_List of specifications (specs) for the completed goal. These are declarative sentences (statements) describing a feature of the final product._ + +**This is a core goal. The specifications are non-negotiable. To complete this goal, you must complete all specs listed below.** + +- [ ] Artifact produced is a fork of the [core-data-structures][core-data-structures] repo. +- [ ] Can run all tests with `npm test`. +- [ ] All tests are passing. +- [ ] For each data structure identified above, there exists: + - [ ] a test file with unit tests for each method and property. + - [ ] an implementation file with a correct implementation of the data structure. + +### Required + +_Do not remove these specs - they are required for all goals_. + +- [ ] The artifact produced is properly licensed, preferably with the [MIT license][mit-license]. + +### Stretch + +Pick a _different_ programming language from JavaScript (e.g. Ruby, Swift, Python, C, Java...) and write tests & implementations for each. + +- [ ] Can run all non-JavaScript tests with a single command. +- [ ] For each data structure identified above, there exists: + - [ ] a test file with unit tests for each method and property _in a language other than JavaScript_. + - [ ] an implementation file with a correct implementation of the data structure _in a language other than JavaScript_. + +## Quality Rubric + +**Well formatted code** +- Code uses a linter, which can be invoked with a command (e.g. `npm run lint`). [50 points] +- Running the linter on all source code files generates no linting errors. [50 points] + +**Clear and useful README** +- Repository includes a README file with installation and setup instructions. [25 points] +- Repository includes a README file with usage instructions and at least one example use case. [25 points] + +**Proper dependency management** +- There is a command to install dependencies (e.g. `npm install`) and it is specified in the installation and setup instructions of the README. [50 points] + +**Good project management** +- Commit messages are concise and descriptive. [25 points] +- All features are added via pull requests. [25 points] +- Every pull request has a description summarizing the changes made. [25 points] +- Every pull request has been reviewed by at least one other person. [25 points] + +--- + + + +Creative Commons License +
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. + +[mit-license]: https://opensource.org/licenses/MIT +[core-data-structures]: https://github.com/GuildCrafts/core-data-structures From 7ee84a6f89bdcc977c1273a9cd4040e370c48f71 Mon Sep 17 00:00:00 2001 From: thamaranth Date: Tue, 17 Jan 2017 18:05:20 -0800 Subject: [PATCH 04/17] added several stack functions with tests --- spec/stack.js | 92 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/stack.js | 34 ++++++++++++++++++- 2 files changed, 123 insertions(+), 3 deletions(-) diff --git a/spec/stack.js b/spec/stack.js index 743122a..04769cc 100644 --- a/spec/stack.js +++ b/spec/stack.js @@ -11,12 +11,100 @@ describe('Stack', () => { expect(Stack).to.be.a('function') }) - context('push()', () => { + describe('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 }) + .to.alter(() => myStack.elements.length, { from: 0, to: 1 }) + expect(() => myStack.push('bar')) + .to.alter(() => myStack.elements.length, { from: 1, to: 2 }) + expect(() => myStack.push('boom')) + .to.alter(() => myStack.elements.length, { from: 2, to: 3 }) + }) + }) + describe('pop()', () => { + it('returns and removes the top element in the stack or null if the stack is empty.', () => { + const myStack = new Stack() + + myStack.push('cereal') + myStack.push('almond milk') + myStack.push('bananas') + // console.log(myStack) + // console.log(myStack.pop()) + // console.log(myStack) + + expect(() => myStack.pop()) + .to.alter(() => myStack.elements.length, { from: 3, to: 2 }) + + }) + it('it does not return undefined', () => { + const myStack = new Stack() + + myStack.push('cereal') + myStack.push('almond milk') + myStack.push('bananas') + // console.log(myStack) + // console.log(myStack.pop()) + // console.log(myStack) + + expect(() => myStack.pop()) + .to.not.be.undefined + }) + it('returns the last value of the stack and null if stack is empty ', () => { + const myStack = new Stack() + + myStack.push('cereal') + myStack.push('almond milk') + myStack.push('bananas') + // console.log(myStack) + // console.log(myStack.pop()) + // console.log(myStack) + + expect(myStack.pop()) + .to.eql(['bananas']) + expect(myStack.pop()) + .to.eql(['almond milk']) + expect(myStack.pop()) + .to.eql(['cereal']) + expect(myStack.pop()) + .to.be.null + }) + }) + describe('peek()', () => { + it('should return the last element in the stack or null if the stack is empty.', () => { + const myStack = new Stack() + const emptyStack = new Stack() + + myStack.push('cereal') + myStack.push('almond milk') + myStack.push('bananas') + // console.log(myStack) + // console.log(myStack.pop()) + // console.log(myStack) + + expect(myStack.peek()) + .to.eql(['bananas']) + expect(emptyStack.peek()) + .to.be.null + }) + }) + describe('peek()', () => { + it('returns true if the stack is empty or false if not.', () => { + const myStack = new Stack() + const emptyStack = new Stack() + + myStack.push('cereal') + myStack.push('almond milk') + myStack.push('bananas') + // console.log(myStack) + // console.log(emptyStack) + // console.log(myStack) + + expect(myStack.isEmpty()) + .to.be.false + expect(emptyStack.isEmpty()) + .to.be.true }) }) }) diff --git a/src/stack.js b/src/stack.js index dcd1d13..28e3344 100644 --- a/src/stack.js +++ b/src/stack.js @@ -1,5 +1,37 @@ 'use strict' export default class Stack { - // your code here + constructor(initialValues=[]) { + this.elements = initialValues + this.top = initialValues.length + } + push(value){ + this.elements[this.top] = value + this.top++ + } + pop(){ + + if(this.top === 0){ + return null + } + + let result = this.elements.slice(-1) + this.elements.splice(-1) + this.top-- + return result + + } + peek(){ + if (this.top === 0){ + return null + } + return this.elements.slice(-1) + } + isEmpty(){ + if (this.top === 0 ){ + return true + } else { + return false + } + } } From 5d67965ff66f09de4d1e4dd9a14145c31b11149c Mon Sep 17 00:00:00 2001 From: thamaranth Date: Wed, 18 Jan 2017 10:01:00 -0800 Subject: [PATCH 05/17] finished Stack functions --- spec/stack.js | 37 +++++++++++++++++++------------------ src/stack.js | 17 ++++++++++++++--- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/spec/stack.js b/spec/stack.js index 04769cc..3e5eb57 100644 --- a/spec/stack.js +++ b/spec/stack.js @@ -7,7 +7,7 @@ chai.use(chaiChange) describe('Stack', () => { 'use strict' - it('exists', () => { + it('exists', () => { expect(Stack).to.be.a('function') }) @@ -30,9 +30,6 @@ describe('Stack', () => { myStack.push('cereal') myStack.push('almond milk') myStack.push('bananas') - // console.log(myStack) - // console.log(myStack.pop()) - // console.log(myStack) expect(() => myStack.pop()) .to.alter(() => myStack.elements.length, { from: 3, to: 2 }) @@ -44,9 +41,6 @@ describe('Stack', () => { myStack.push('cereal') myStack.push('almond milk') myStack.push('bananas') - // console.log(myStack) - // console.log(myStack.pop()) - // console.log(myStack) expect(() => myStack.pop()) .to.not.be.undefined @@ -57,9 +51,6 @@ describe('Stack', () => { myStack.push('cereal') myStack.push('almond milk') myStack.push('bananas') - // console.log(myStack) - // console.log(myStack.pop()) - // console.log(myStack) expect(myStack.pop()) .to.eql(['bananas']) @@ -79,17 +70,14 @@ describe('Stack', () => { myStack.push('cereal') myStack.push('almond milk') myStack.push('bananas') - // console.log(myStack) - // console.log(myStack.pop()) - // console.log(myStack) expect(myStack.peek()) - .to.eql(['bananas']) + .to.eql('bananas') expect(emptyStack.peek()) .to.be.null }) }) - describe('peek()', () => { + describe('isEmpty()', () => { it('returns true if the stack is empty or false if not.', () => { const myStack = new Stack() const emptyStack = new Stack() @@ -97,9 +85,6 @@ describe('Stack', () => { myStack.push('cereal') myStack.push('almond milk') myStack.push('bananas') - // console.log(myStack) - // console.log(emptyStack) - // console.log(myStack) expect(myStack.isEmpty()) .to.be.false @@ -107,4 +92,20 @@ describe('Stack', () => { .to.be.true }) }) + + describe('length()', () => { + it('returns the number of elements in the stack.', () => { + const myStack = new Stack() + const emptyStack = new Stack() + + myStack.push('cereal') + myStack.push('almond milk') + myStack.push('bananas') + + expect(myStack.length()) + .to.eql(3) + expect(emptyStack.length()) + .to.eql(0) + }) + }) }) diff --git a/src/stack.js b/src/stack.js index 28e3344..979ac12 100644 --- a/src/stack.js +++ b/src/stack.js @@ -5,28 +5,30 @@ export default class Stack { this.elements = initialValues this.top = initialValues.length } + push(value){ this.elements[this.top] = value this.top++ } - pop(){ + pop(){ if(this.top === 0){ return null } - let result = this.elements.slice(-1) this.elements.splice(-1) this.top-- return result } + peek(){ if (this.top === 0){ return null } - return this.elements.slice(-1) + return this.elements[this.top -1] } + isEmpty(){ if (this.top === 0 ){ return true @@ -34,4 +36,13 @@ export default class Stack { return false } } + + length(){ + let count = 0 + for (var key in this.elements) { + count++ + } + return count + } + } From 30c27234960279e55a47ce12205c79dfd98d2b2e Mon Sep 17 00:00:00 2001 From: thamaranth Date: Wed, 18 Jan 2017 11:36:40 -0800 Subject: [PATCH 06/17] renamed test files and added in Queue function --- spec/queue_test.js | 110 +++++++++++++++++++++++++++++++ spec/{stack.js => stack_test.js} | 0 src/queue.js | 55 ++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 spec/queue_test.js rename spec/{stack.js => stack_test.js} (100%) create mode 100644 src/queue.js diff --git a/spec/queue_test.js b/spec/queue_test.js new file mode 100644 index 0000000..61c34fb --- /dev/null +++ b/spec/queue_test.js @@ -0,0 +1,110 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Queue from '../src/queue' + +chai.use(chaiChange) + +describe('Queue', () => { + 'use strict' + + it('exists', () => { + expect(Queue).to.be.a('function') + }) + + describe('enqueue()', () => { + it('adds an element to the back of the queue.', () => { + const queue = new Queue() + expect(() => queue.enqueue('foo')) + .to.alter(() => queue.elements.length, { from: 0, to: 1 }) + expect(() => queue.enqueue('bar')) + .to.alter(() => queue.elements.length, { from: 1, to: 2 }) + expect(queue.elements[queue.elements.length - 1]) + .to.eql('bar') + + }) + }) + + describe('dequeue()', () => { + it('returns and removes the front element in the queue or null if the queue is empty.', () => { + const queue = new Queue() + + queue.enqueue('cereal') + queue.enqueue('almond milk') + queue.enqueue('bananas') + + expect(() => queue.dequeue()) + .to.alter(() => queue.elements.length, { from: 3, to: 2 }) + expect(() => queue.dequeue()) + .to.alter(() => queue.elements.length, { from: 2, to: 1 }) + expect(() => queue.dequeue()) + .to.alter(() => queue.elements.length, { from: 1, to: 0 }) + expect(queue.dequeue()) + .to.be.null + }) + }) + + describe('front()', () => { + it('returns the front element in queue or null if the queue is empty.', () => { + const queue = new Queue() + const emptyQueue = new Queue() + + queue.enqueue('cereal') + queue.enqueue('almond milk') + queue.enqueue('bananas') + + expect(queue.front()) + .to.eql('cereal') + expect(emptyQueue.front()) + .to.be.null + }) + }) + + describe('back()', () => { + it('returns the front element in queue or null if the queue is empty.', () => { + const queue = new Queue() + const emptyQueue = new Queue() + + queue.enqueue('cereal') + queue.enqueue('almond milk') + queue.enqueue('bananas') + + expect(queue.back()) + .to.eql('bananas') + expect(emptyQueue.back()) + .to.be.null + }) + }) + + describe('isEmpty()', () => { + it('returns true if the queue is empty or false if not.', () => { + const queue = new Queue() + const emptyQueue = new Queue() + + queue.enqueue('cereal') + queue.enqueue('almond milk') + queue.enqueue('bananas') + + expect(queue.isEmpty()) + .to.be.false + expect(emptyQueue.isEmpty()) + .to.be.true + }) + }) + + describe('length()', () => { + it('returns the number of elements in the queue', () => { + const queue = new Queue() + const emptyQueue = new Queue() + + queue.enqueue('cereal') + queue.enqueue('almond milk') + queue.enqueue('bananas') + + expect(queue.length()) + .to.eql(3) + expect(emptyQueue.length()) + .to.eql(0) + }) + }) + +}) diff --git a/spec/stack.js b/spec/stack_test.js similarity index 100% rename from spec/stack.js rename to spec/stack_test.js diff --git a/src/queue.js b/src/queue.js new file mode 100644 index 0000000..6c75339 --- /dev/null +++ b/src/queue.js @@ -0,0 +1,55 @@ +'use strict' + +export default class Queue { + constructor(initialValues=[]) { + this.elements = initialValues + this.first = initialValues[0] + this.last = initialValues.length + } + enqueue(value){ + this.elements[this.last] = value + this.last++ + } + + dequeue(){ + if(this.elements.length === 0 ){ + return null + } + let result = this.elements.slice(0, 1) + this.elements.splice(0,1) + return result + } + + front(){ + if(this.elements.length === 0){ + return null + } else { + return this.elements[0] + } + } + + back(){ + if(this.elements.length === 0){ + return null + } else { + return this.elements[this.last - 1] + } + } + + isEmpty(){ + if (this.elements.length === 0 ){ + return true + } else { + return false + } + } + + length(){ + let count = 0 + for (var key in this.elements) { + count++ + } + return count + } + +} From 79194e52b9ec68ccf1fb5b2ab6e1c3f9d73b7cfa Mon Sep 17 00:00:00 2001 From: Breyana Scales Date: Wed, 18 Jan 2017 14:08:46 -0800 Subject: [PATCH 07/17] added in Deonna's suggestions for formatting and cleaner code --- spec/queue_test.js | 28 +++++++++--------- src/queue.js | 71 ++++++++++++++++++++++------------------------ src/stack.js | 10 +++---- 3 files changed, 53 insertions(+), 56 deletions(-) diff --git a/spec/queue_test.js b/spec/queue_test.js index 61c34fb..f14b641 100644 --- a/spec/queue_test.js +++ b/spec/queue_test.js @@ -19,7 +19,7 @@ describe('Queue', () => { expect(() => queue.enqueue('bar')) .to.alter(() => queue.elements.length, { from: 1, to: 2 }) expect(queue.elements[queue.elements.length - 1]) - .to.eql('bar') + .to.equal('bar') }) }) @@ -34,12 +34,12 @@ describe('Queue', () => { expect(() => queue.dequeue()) .to.alter(() => queue.elements.length, { from: 3, to: 2 }) - expect(() => queue.dequeue()) - .to.alter(() => queue.elements.length, { from: 2, to: 1 }) - expect(() => queue.dequeue()) - .to.alter(() => queue.elements.length, { from: 1, to: 0 }) - expect(queue.dequeue()) - .to.be.null + expect(() => queue.dequeue()) + .to.alter(() => queue.elements.length, { from: 2, to: 1 }) + expect(() => queue.dequeue()) + .to.alter(() => queue.elements.length, { from: 1, to: 0 }) + expect(queue.dequeue()) + .to.be.null }) }) @@ -53,7 +53,7 @@ describe('Queue', () => { queue.enqueue('bananas') expect(queue.front()) - .to.eql('cereal') + .to.equal('cereal') expect(emptyQueue.front()) .to.be.null }) @@ -69,7 +69,7 @@ describe('Queue', () => { queue.enqueue('bananas') expect(queue.back()) - .to.eql('bananas') + .to.equal('bananas') expect(emptyQueue.back()) .to.be.null }) @@ -86,8 +86,8 @@ describe('Queue', () => { expect(queue.isEmpty()) .to.be.false - expect(emptyQueue.isEmpty()) - .to.be.true + expect(emptyQueue.isEmpty()) + .to.be.true }) }) @@ -101,9 +101,9 @@ describe('Queue', () => { queue.enqueue('bananas') expect(queue.length()) - .to.eql(3) - expect(emptyQueue.length()) - .to.eql(0) + .to.equal(3) + expect(emptyQueue.length()) + .to.equal(0) }) }) diff --git a/src/queue.js b/src/queue.js index 6c75339..5f69c5b 100644 --- a/src/queue.js +++ b/src/queue.js @@ -3,53 +3,50 @@ export default class Queue { constructor(initialValues=[]) { this.elements = initialValues - this.first = initialValues[0] - this.last = initialValues.length } - enqueue(value){ - this.elements[this.last] = value - this.last++ - } - dequeue(){ - if(this.elements.length === 0 ){ - return null - } - let result = this.elements.slice(0, 1) - this.elements.splice(0,1) - return result + enqueue(value) { + this.elements[this.elements.length] = value + this.last++ + } + + dequeue() { + if(this.elements.length === 0 ){ + return null } + let result = this.elements.slice(0, 1) + this.elements.splice(0,1) + return result + } - front(){ - if(this.elements.length === 0){ - return null - } else { - return this.elements[0] - } + front() { + if(this.elements.length){ + return this.elements[0] } - back(){ - if(this.elements.length === 0){ - return null - } else { - return this.elements[this.last - 1] - } + return null + } + + back() { + if(this.elements.length){ + return this.elements.slice(-1)[0] } + return null + } - isEmpty(){ - if (this.elements.length === 0 ){ - return true - } else { - return false - } + isEmpty() { + if (this.elements.length){ + return false } + return true + } - length(){ - let count = 0 - for (var key in this.elements) { - count++ - } - return count + length() { + let count = 0 + for (let key in this.elements) { + count++ } + return count + } } diff --git a/src/stack.js b/src/stack.js index 979ac12..bed1ce7 100644 --- a/src/stack.js +++ b/src/stack.js @@ -6,12 +6,12 @@ export default class Stack { this.top = initialValues.length } - push(value){ + push(value) { this.elements[this.top] = value this.top++ } - pop(){ + pop() { if(this.top === 0){ return null } @@ -22,14 +22,14 @@ export default class Stack { } - peek(){ + peek() { if (this.top === 0){ return null } return this.elements[this.top -1] } - isEmpty(){ + isEmpty() { if (this.top === 0 ){ return true } else { @@ -37,7 +37,7 @@ export default class Stack { } } - length(){ + length() { let count = 0 for (var key in this.elements) { count++ From f179393538d9228ed1a6a489571cdee0e400293e Mon Sep 17 00:00:00 2001 From: Breyana Scales Date: Wed, 18 Jan 2017 14:15:19 -0800 Subject: [PATCH 08/17] refactored Stack --- src/stack.js | 58 +++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/stack.js b/src/stack.js index bed1ce7..29c06eb 100644 --- a/src/stack.js +++ b/src/stack.js @@ -3,46 +3,44 @@ export default class Stack { constructor(initialValues=[]) { this.elements = initialValues - this.top = initialValues.length } - push(value) { - this.elements[this.top] = value - this.top++ - } + push(value) { + this.elements[this.elements.length] = value - pop() { - if(this.top === 0){ - return null - } - let result = this.elements.slice(-1) - this.elements.splice(-1) - this.top-- - return result + } + pop() { + if(this.elements.length === 0){ + return null } + let result = this.elements.slice(-1) + this.elements.splice(-1) + return result + + } - peek() { - if (this.top === 0){ - return null - } - return this.elements[this.top -1] + peek() { + if (this.elements.length === 0){ + return null } + return this.elements[this.elements.length -1] + } - isEmpty() { - if (this.top === 0 ){ - return true - } else { - return false - } + isEmpty() { + if (this.elements.length === 0 ){ + return true + } else { + return false } + } - length() { - let count = 0 - for (var key in this.elements) { - count++ - } - return count + length() { + let count = 0 + for (var key in this.elements) { + count++ } + return count + } } From 71ff38d51761fdb2063ec4fd432c8bb0944e8985 Mon Sep 17 00:00:00 2001 From: Breyana Scales Date: Wed, 18 Jan 2017 15:59:09 -0800 Subject: [PATCH 09/17] WIP for PQueue --- src/pQueue.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/queue.js | 1 - src/stack.js | 1 - 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 src/pQueue.js diff --git a/src/pQueue.js b/src/pQueue.js new file mode 100644 index 0000000..cbf112d --- /dev/null +++ b/src/pQueue.js @@ -0,0 +1,51 @@ +'use strict' + +export default class PriorityQueue { + constructor(initialValues = []) { + this.elements = initialValues + } + + enqueue(value, priority) { + this.elements[this.elements.length] = [value, priority] + } + + front() { + if (this.elements.length){ + let highest = this.elements[0] + for(let pair of this.elements) { + if (pair[1] > highest[1]) { + highest = pair + } + } + return highest + } + return null + } + + back() { + if (this.elements.length){ + let lowest = this.elements[0] + for(let pair of this.elements) { + if (pair[1] < lowest[1]) { + lowest = pair + } + } + return lowest + } + return null + } + + dequeue() { + if (this.elements.length){ + let highest = this.elements[0] + for(let pair of this.elements) { + if (pair[1] > highest[1]) { + highest = pair + highest.splice() + } + } + return highest.slice() + } + return null + } +} diff --git a/src/queue.js b/src/queue.js index 5f69c5b..888d90c 100644 --- a/src/queue.js +++ b/src/queue.js @@ -7,7 +7,6 @@ export default class Queue { enqueue(value) { this.elements[this.elements.length] = value - this.last++ } dequeue() { diff --git a/src/stack.js b/src/stack.js index 29c06eb..0fa344b 100644 --- a/src/stack.js +++ b/src/stack.js @@ -7,7 +7,6 @@ export default class Stack { push(value) { this.elements[this.elements.length] = value - } pop() { From 3a605c222b259b055b3728fb62cfa7f3e1c65d2f Mon Sep 17 00:00:00 2001 From: Breyana Scales Date: Wed, 18 Jan 2017 16:15:52 -0800 Subject: [PATCH 10/17] WIP for PQueue --- spec/pQueue_test.js | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 spec/pQueue_test.js diff --git a/spec/pQueue_test.js b/spec/pQueue_test.js new file mode 100644 index 0000000..9e354da --- /dev/null +++ b/spec/pQueue_test.js @@ -0,0 +1,78 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import PriorityQueue from '../src/pQueue' + +chai.use(chaiChange) + +describe('Priority Queue', () => { + 'use strict' + + it('exists', () => { + expect(PriorityQueue).to.be.a('function') + }) + + describe('enqueue()', () => { + it('adds an element with priority (number) to the back of the queue.', () => { + const pQueue = new PriorityQueue() + expect(() => pQueue.enqueue('foo', 200)) + .to.alter(() => pQueue.elements.length, { from: 0, to: 1 }) + expect(() => pQueue.enqueue('bar', 100)) + .to.alter(() => pQueue.elements.length, { from: 1, to: 2 }) + expect(pQueue.elements[pQueue.elements.length - 1]) + .to.deep.equal(['bar', 100]) + }) + }) + + describe('front()', () => { + it('returns the front element (highest priority) in the queue or null if the queue is empty.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal', 100) + pQueue.enqueue('almond milk', 300) + pQueue.enqueue('blueberries', 400) + pQueue.enqueue('bananas', 200) + + expect(pQueue.front()) + .to.deep.equal(['blueberries', 400]) + expect(emptyPQueue.front()) + .to.be.null + + }) + }) + + describe('back()', () => { + it('returns the back element (lowest priority) in the queue or null if the queue is empty.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal', 100) + pQueue.enqueue('almond milk', 300) + pQueue.enqueue('blueberries', 400) + pQueue.enqueue('bananas', 200) + + expect(pQueue.back()) + .to.deep.equal(['cereal', 100]) + expect(emptyPQueue.back()) + .to.be.null + + }) + }) + + describe.only('dequeue()', () => { + it('returns and removes the front element (highest priority) in the queue or null if the queue is empty.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal', 100) + pQueue.enqueue('almond milk', 300) + pQueue.enqueue('blueberries', 400) + pQueue.enqueue('bananas', 200) + + expect(pQueue.dequeue()) + .to.deep.equal(['blueberries', 400]) + expect(pQueue.dequeue()) + .to.alter(() => pQueue.elements.length, { from: 4, to: 3}) + }) + }) +}) From 333d6c229257f1621f6ae2cdec0c4c9d5cd043e3 Mon Sep 17 00:00:00 2001 From: thamaranth Date: Thu, 19 Jan 2017 08:38:43 -0800 Subject: [PATCH 11/17] WIP for PQueue --- spec/pQueue_test.js | 4 ++-- src/pQueue.js | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/spec/pQueue_test.js b/spec/pQueue_test.js index 9e354da..70749de 100644 --- a/spec/pQueue_test.js +++ b/spec/pQueue_test.js @@ -71,8 +71,8 @@ describe('Priority Queue', () => { expect(pQueue.dequeue()) .to.deep.equal(['blueberries', 400]) - expect(pQueue.dequeue()) - .to.alter(() => pQueue.elements.length, { from: 4, to: 3}) + expect(() => pQueue.dequeue()) + .to.alter(() => pQueue.elements.length, { from: 3, to: 2}) }) }) }) diff --git a/src/pQueue.js b/src/pQueue.js index cbf112d..5d623a3 100644 --- a/src/pQueue.js +++ b/src/pQueue.js @@ -37,14 +37,20 @@ export default class PriorityQueue { dequeue() { if (this.elements.length){ + // for(i=0; i < this.elements.length; i++){ + // + // } + // } let highest = this.elements[0] + for(let pair of this.elements) { if (pair[1] > highest[1]) { highest = pair - highest.splice() } } - return highest.slice() + const popped = highest.slice() + this.elements.splice(this.elements.indexOf(highest),1) + return popped } return null } From c77a6538c76ee73e553692b7302b890300abdd30 Mon Sep 17 00:00:00 2001 From: Breyana Scales Date: Thu, 19 Jan 2017 12:08:40 -0800 Subject: [PATCH 12/17] set WIP --- spec/pQueue_test.js | 40 +++++++++++++++++-- spec/queue_test.js | 1 + spec/set_test.js | 97 +++++++++++++++++++++++++++++++++++++++++++++ src/pQueue.js | 24 +++++++---- src/set.js | 60 ++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 10 deletions(-) create mode 100644 spec/set_test.js create mode 100644 src/set.js diff --git a/spec/pQueue_test.js b/spec/pQueue_test.js index 70749de..34fe655 100644 --- a/spec/pQueue_test.js +++ b/spec/pQueue_test.js @@ -59,7 +59,7 @@ describe('Priority Queue', () => { }) }) - describe.only('dequeue()', () => { + describe('dequeue()', () => { it('returns and removes the front element (highest priority) in the queue or null if the queue is empty.', () => { const pQueue = new PriorityQueue() const emptyPQueue = new PriorityQueue() @@ -68,11 +68,45 @@ describe('Priority Queue', () => { pQueue.enqueue('almond milk', 300) pQueue.enqueue('blueberries', 400) pQueue.enqueue('bananas', 200) + pQueue.enqueue('spoon', 500) expect(pQueue.dequeue()) - .to.deep.equal(['blueberries', 400]) + .to.deep.equal(['spoon', 500]) expect(() => pQueue.dequeue()) - .to.alter(() => pQueue.elements.length, { from: 3, to: 2}) + .to.alter(() => pQueue.elements.length, { from: 4, to: 3}) + }) + }) + + describe('isEmpty()', () => { + it('returns true if the queue is empty or false if not.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal') + pQueue.enqueue('almond milk') + pQueue.enqueue('bananas') + + expect(pQueue.isEmpty()) + .to.be.false + expect(emptyPQueue.isEmpty()) + .to.be.true }) }) + + describe('length()', () => { + it('returns the number of elements in the queue', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal') + pQueue.enqueue('almond milk') + pQueue.enqueue('bananas') + + expect(pQueue.length()) + .to.equal(3) + expect(emptyPQueue.length()) + .to.equal(0) + }) + }) + }) diff --git a/spec/queue_test.js b/spec/queue_test.js index f14b641..50d5b84 100644 --- a/spec/queue_test.js +++ b/spec/queue_test.js @@ -14,6 +14,7 @@ describe('Queue', () => { describe('enqueue()', () => { it('adds an element to the back of the queue.', () => { const queue = new Queue() + expect(() => queue.enqueue('foo')) .to.alter(() => queue.elements.length, { from: 0, to: 1 }) expect(() => queue.enqueue('bar')) diff --git a/spec/set_test.js b/spec/set_test.js new file mode 100644 index 0000000..fb6b7e1 --- /dev/null +++ b/spec/set_test.js @@ -0,0 +1,97 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Set from '../src/set' + +chai.use(chaiChange) + +describe('Set', () => { + 'use strict' + + it('exists', () => { + expect(Set).to.be.a('function') + }) + + describe('add()', () => { + it('adds an element to the set -- if it does not already exist', () => { + const set = new Set(['A', 'B', 'C']) + + expect(() => set.add('D')) + .to.alter(() => set.elements.length, { from: 3, to: 4 }) + expect( set.add('D')) + .to.be.false + expect(set.elements[set.elements.length - 1]) + .to.equal('D') + + }) + }) + + describe('isEmpty()', () => { + it('returns true if the set is empty or false if not.', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set() + + expect(set.isEmpty()) + .to.be.false + expect(otherSet.isEmpty()) + .to.be.true + }) + }) + + describe('contains()', () => { + it('returns true the set contains the element or false if not.', () => { + const set = new Set(['A', 'B', 'C', 'D']) + + expect(set.contains('F')) + .to.be.false + expect(set.contains('D')) + .to.be.true + }) + }) + + describe('remove()', () => { + it('removes an element (if it exists) from the set.', () => { + const set = new Set(['A', 'B', 'C', 'D']) + + expect(() => set.remove('D')) + .to.alter(() => set.elements.length, { from: 4, to: 3 }) + expect(set.remove('G')) + .to.equal("The value to remove does not exist") + }) + }) + + describe('forEach()', () => { + it('takes a callback function and passes it each element in sequence.', () => { + const set = new Set(['A', 'B', 'C', 'D']) + const result = [] + const test = element => result.push( element ) + + set.forEach( test ) + + expect( result ) + .to.have.members(['A','B','C','D']) + }) + }) + + describe('size()', () => { + it('returns the number of elements in the set', () => { + const set = new Set(['A', 'B', 'C', 'D']) + const emptySet = new Set([]) + + + expect(set.size()) + .to.equal(4) + expect(emptySet.size()) + .to.equal(0) + }) + }) + + describe.only('union()', () => { + it('unions the set with another set and returns the resulting set.', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['B', 'C', 'D']) + + expect(set.union(otherSet)) + .to.equal(['A', 'B', 'C', 'D']) + }) + }) +}) diff --git a/src/pQueue.js b/src/pQueue.js index 5d623a3..84d2cb5 100644 --- a/src/pQueue.js +++ b/src/pQueue.js @@ -37,21 +37,31 @@ export default class PriorityQueue { dequeue() { if (this.elements.length){ - // for(i=0; i < this.elements.length; i++){ - // - // } - // } let highest = this.elements[0] - for(let pair of this.elements) { if (pair[1] > highest[1]) { highest = pair } } - const popped = highest.slice() this.elements.splice(this.elements.indexOf(highest),1) - return popped + return highest } return null } + + isEmpty() { + if (this.elements.length){ + return false + } + return true + } + + length() { + let count = 0 + for (let key in this.elements) { + count++ + } + return count + } + } diff --git a/src/set.js b/src/set.js new file mode 100644 index 0000000..c6f7697 --- /dev/null +++ b/src/set.js @@ -0,0 +1,60 @@ +'use strict' + +export default class Set { + constructor(initialValues=[]) { + this.elements = initialValues + } + + add(value) { + if (this.elements.indexOf(value) === -1) { + this.elements[this.elements.length] = value + return this.elements + } + return false + } + + isEmpty() { + if (this.elements.length === 0 ){ + return true + } + return false + + + } + + contains(value) { + if (this.elements.indexOf(value) > 0) { + return true + } + return false + } + + remove(value) { + if (this.elements.indexOf(value) > 0) { + return this.elements.splice(this.elements.indexOf(value),1) + } + return "The value to remove does not exist" + } + + forEach(func) { + this.elements = this.elements.map(func) + return this.elements + } + + size() { + let count = 0 + for (let key in this.elements) { + count++ + } + return count + } + + union(secondSet) { + let unioned = this.elements + for (var elem of secondSet) + if (unioned.indexOf(elem) === -1) { + unioned[unioned.length] = elem + } + return unioned + } +} From 794fdf09c4abe18699c1a139b800a90b6e770dd3 Mon Sep 17 00:00:00 2001 From: thamaranth Date: Thu, 19 Jan 2017 15:01:03 -0800 Subject: [PATCH 13/17] WIP for Set --- spec/set_test.js | 3 ++- src/set.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/set_test.js b/spec/set_test.js index fb6b7e1..be1f6fb 100644 --- a/spec/set_test.js +++ b/spec/set_test.js @@ -89,9 +89,10 @@ describe('Set', () => { it('unions the set with another set and returns the resulting set.', () => { const set = new Set(['A', 'B', 'C']) const otherSet = new Set(['B', 'C', 'D']) + console.log(set.union(otherSet)) expect(set.union(otherSet)) - .to.equal(['A', 'B', 'C', 'D']) + .to.deep.equal(['A', 'B', 'C', 'D']) }) }) }) diff --git a/src/set.js b/src/set.js index c6f7697..47d74cd 100644 --- a/src/set.js +++ b/src/set.js @@ -51,10 +51,11 @@ export default class Set { union(secondSet) { let unioned = this.elements - for (var elem of secondSet) + for (var elem of secondSet.elements) if (unioned.indexOf(elem) === -1) { unioned[unioned.length] = elem } return unioned } + } From 6b6e0bc454643ca2afa1a9c01e423760549881d0 Mon Sep 17 00:00:00 2001 From: breyana Date: Wed, 25 Jan 2017 17:19:26 -0800 Subject: [PATCH 14/17] Day2 data structures (#3) * WIP for PQueue * WIP for PQueue * set WIP * WIP for Set * Linked List --- spec/linkedList_test.js | 28 +++++++ spec/pQueue_test.js | 112 ++++++++++++++++++++++++++++ spec/queue_test.js | 1 + spec/set_test.js | 160 ++++++++++++++++++++++++++++++++++++++++ src/linkedList.js | 83 +++++++++++++++++++++ src/pQueue.js | 20 ++++- src/set.js | 103 ++++++++++++++++++++++++++ 7 files changed, 505 insertions(+), 2 deletions(-) create mode 100644 spec/linkedList_test.js create mode 100644 spec/pQueue_test.js create mode 100644 spec/set_test.js create mode 100644 src/linkedList.js create mode 100644 src/set.js diff --git a/spec/linkedList_test.js b/spec/linkedList_test.js new file mode 100644 index 0000000..96ceb4f --- /dev/null +++ b/spec/linkedList_test.js @@ -0,0 +1,28 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import LinkedList from '../src/linkedList' + +chai.use(chaiChange) + +describe('Linked List', () => { + 'use strict' + + it('exists', () => { + expect(LinkedList).to.be.a('function') + }) + + describe('insert()', () => { + it('Inserts a node (with the provided data) to the tail of the list', () => { + const linkedList = new LinkedList() + + expect(() => linkedList.insert('foo')) + .to.alter(() => linkedList.count, { from: 0, to: 1 }) + expect(linkedList.getHeadNode().data) + .to.equal('foo') + expect(() => linkedList.insert('boo')) + .to.alter(() => linkedList.count, { from: 1, to: 2 }) + expect(linkedList.getTailNode().data) + .to.equal('boo') + }) + }) +}) diff --git a/spec/pQueue_test.js b/spec/pQueue_test.js new file mode 100644 index 0000000..34fe655 --- /dev/null +++ b/spec/pQueue_test.js @@ -0,0 +1,112 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import PriorityQueue from '../src/pQueue' + +chai.use(chaiChange) + +describe('Priority Queue', () => { + 'use strict' + + it('exists', () => { + expect(PriorityQueue).to.be.a('function') + }) + + describe('enqueue()', () => { + it('adds an element with priority (number) to the back of the queue.', () => { + const pQueue = new PriorityQueue() + expect(() => pQueue.enqueue('foo', 200)) + .to.alter(() => pQueue.elements.length, { from: 0, to: 1 }) + expect(() => pQueue.enqueue('bar', 100)) + .to.alter(() => pQueue.elements.length, { from: 1, to: 2 }) + expect(pQueue.elements[pQueue.elements.length - 1]) + .to.deep.equal(['bar', 100]) + }) + }) + + describe('front()', () => { + it('returns the front element (highest priority) in the queue or null if the queue is empty.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal', 100) + pQueue.enqueue('almond milk', 300) + pQueue.enqueue('blueberries', 400) + pQueue.enqueue('bananas', 200) + + expect(pQueue.front()) + .to.deep.equal(['blueberries', 400]) + expect(emptyPQueue.front()) + .to.be.null + + }) + }) + + describe('back()', () => { + it('returns the back element (lowest priority) in the queue or null if the queue is empty.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal', 100) + pQueue.enqueue('almond milk', 300) + pQueue.enqueue('blueberries', 400) + pQueue.enqueue('bananas', 200) + + expect(pQueue.back()) + .to.deep.equal(['cereal', 100]) + expect(emptyPQueue.back()) + .to.be.null + + }) + }) + + describe('dequeue()', () => { + it('returns and removes the front element (highest priority) in the queue or null if the queue is empty.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal', 100) + pQueue.enqueue('almond milk', 300) + pQueue.enqueue('blueberries', 400) + pQueue.enqueue('bananas', 200) + pQueue.enqueue('spoon', 500) + + expect(pQueue.dequeue()) + .to.deep.equal(['spoon', 500]) + expect(() => pQueue.dequeue()) + .to.alter(() => pQueue.elements.length, { from: 4, to: 3}) + }) + }) + + describe('isEmpty()', () => { + it('returns true if the queue is empty or false if not.', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal') + pQueue.enqueue('almond milk') + pQueue.enqueue('bananas') + + expect(pQueue.isEmpty()) + .to.be.false + expect(emptyPQueue.isEmpty()) + .to.be.true + }) + }) + + describe('length()', () => { + it('returns the number of elements in the queue', () => { + const pQueue = new PriorityQueue() + const emptyPQueue = new PriorityQueue() + + pQueue.enqueue('cereal') + pQueue.enqueue('almond milk') + pQueue.enqueue('bananas') + + expect(pQueue.length()) + .to.equal(3) + expect(emptyPQueue.length()) + .to.equal(0) + }) + }) + +}) diff --git a/spec/queue_test.js b/spec/queue_test.js index f14b641..50d5b84 100644 --- a/spec/queue_test.js +++ b/spec/queue_test.js @@ -14,6 +14,7 @@ describe('Queue', () => { describe('enqueue()', () => { it('adds an element to the back of the queue.', () => { const queue = new Queue() + expect(() => queue.enqueue('foo')) .to.alter(() => queue.elements.length, { from: 0, to: 1 }) expect(() => queue.enqueue('bar')) diff --git a/spec/set_test.js b/spec/set_test.js new file mode 100644 index 0000000..cc90617 --- /dev/null +++ b/spec/set_test.js @@ -0,0 +1,160 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import Set from '../src/set' + +chai.use(chaiChange) + +describe('Set', () => { + 'use strict' + + it('exists', () => { + expect(Set).to.be.a('function') + }) + + describe('add()', () => { + it('adds an element to the set -- if it does not already exist', () => { + const set = new Set(['A', 'B', 'C']) + + expect(() => set.add('D')) + .to.alter(() => set.elements.length, { from: 3, to: 4 }) + expect( set.add('D')) + .to.be.false + expect(set.elements[set.elements.length - 1]) + .to.equal('D') + + }) + }) + + describe('isEmpty()', () => { + it('returns true if the set is empty or false if not.', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set() + + expect(set.isEmpty()) + .to.be.false + expect(otherSet.isEmpty()) + .to.be.true + }) + }) + + describe('contains()', () => { + it('returns true the set contains the element or false if not.', () => { + const set = new Set(['A', 'B', 'C', 'D']) + + expect(set.contains('F')) + .to.be.false + expect(set.contains('D')) + .to.be.true + }) + }) + + describe('remove()', () => { + it('removes an element (if it exists) from the set.', () => { + const set = new Set(['A', 'B', 'C', 'D']) + + expect(() => set.remove('D')) + .to.alter(() => set.elements.length, { from: 4, to: 3 }) + expect(set.remove('G')) + .to.equal("The value to remove does not exist") + }) + }) + + describe('forEach()', () => { + it('takes a callback function and passes it each element in sequence.', () => { + const set = new Set(['A', 'B', 'C', 'D']) + const result = [] + const test = element => result.push( element ) + + set.forEach( test ) + + expect( result ) + .to.have.members(['A','B','C','D']) + }) + }) + + describe('size()', () => { + it('returns the number of elements in the set', () => { + const set = new Set(['A', 'B', 'C', 'D']) + const emptySet = new Set([]) + + + expect(set.size()) + .to.equal(4) + expect(emptySet.size()) + .to.equal(0) + }) + }) + + describe('union()', () => { + it('unions the set with another set and returns the resulting set.', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['B', 'C', 'D']) + + expect(set.union(otherSet)) + .to.deep.equal(['A', 'B', 'C', 'D']) + }) + }) + + describe('intersect()', () => { + it('intersects the set with another set and returns the resulting set.', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['B', 'C', 'D']) + + expect(set.intersect(otherSet)) + .to.deep.equal(['B', 'C']) + }) + }) + + describe('difference()', () => { + it('returns a set that contains the elements found in the set but not in otherSet.', () => { + const set = new Set(['A', 'A', 'B', 'C']) + const otherSet = new Set(['B', 'C', 'D']) + + expect(set.difference(otherSet)) + .to.deep.equal(['A', 'D']) + }) + }) + + describe('isSubset()', () => { + it('returns true if the set is a subset of otherSet or false if not.', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['B', 'C']) + + expect(set.isSubset(otherSet)) + .to.be.true + }) + it('returns false', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['B', 'C', 'D']) + + expect(set.isSubset(otherSet)) + .to.be.false + }) + + it('returns true', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['A', 'C']) + + expect(set.isSubset(otherSet)) + .to.be.true + }) + + it('returns false', () => { + const set = new Set(['A', 'B', 'C']) + const otherSet = new Set(['A', 'C','F']) + + expect(set.isSubset(otherSet)) + .to.be.false + }) + }) + + describe('clone()', () => { + it('returns a cloned set.', () => { + const set = new Set(['A', 'B', 'C']) + + expect(set.clone()) + .to.deep.equal(['A', 'B', 'C']) + }) + }) + +}) diff --git a/src/linkedList.js b/src/linkedList.js new file mode 100644 index 0000000..3be005c --- /dev/null +++ b/src/linkedList.js @@ -0,0 +1,83 @@ +'use strict' + +class Node { + constructor(data) { + this.data = data + this.next = null + } +} + +export default class LinkedList { + constructor() { + this.count = 0 + this.head = null + this.tail = null + } + + getHeadNode() { + return this.head + } + + getTailNode() { + return this.tail + } + + contains() { + + } + + find() { + + } + + insert(item) { + const newNode = new Node(item) + if (this.head === null) { + this.head = newNode + } else { + this.tail.next = newNode + } + this.tail = newNode + this.count++ + // if (this.count = 0){ + // this.head = newNode + // this.tail = newNode + // } else { + // this.tail = newNode + // } + return newNode + } + + insertFirst() { + + } + + insertBefore() { + + } + + insertAfter() { + + } + + remove() { + + } + + removeFirst() { + + } + + isEmpty() { + + } + + size() { + + } + + clear() { + + } + +} diff --git a/src/pQueue.js b/src/pQueue.js index cbf112d..84d2cb5 100644 --- a/src/pQueue.js +++ b/src/pQueue.js @@ -41,11 +41,27 @@ export default class PriorityQueue { for(let pair of this.elements) { if (pair[1] > highest[1]) { highest = pair - highest.splice() } } - return highest.slice() + this.elements.splice(this.elements.indexOf(highest),1) + return highest } return null } + + isEmpty() { + if (this.elements.length){ + return false + } + return true + } + + length() { + let count = 0 + for (let key in this.elements) { + count++ + } + return count + } + } diff --git a/src/set.js b/src/set.js new file mode 100644 index 0000000..ad61ce7 --- /dev/null +++ b/src/set.js @@ -0,0 +1,103 @@ +'use strict' + +export default class Set { + constructor(initialValues=[]) { + this.elements = initialValues + } + + add(value) { + if (this.elements.indexOf(value) === -1) { + this.elements[this.elements.length] = value + return this.elements + } + return false + } + + isEmpty() { + if (this.elements.length === 0 ){ + return true + } + return false + + + } + + contains(value) { + if (this.elements.indexOf(value) > 0) { + return true + } + return false + } + + remove(value) { + if (this.elements.indexOf(value) > 0) { + return this.elements.splice(this.elements.indexOf(value),1) + } + return "The value to remove does not exist" + } + + forEach(func) { + this.elements = this.elements.map(func) + return this.elements + } + + size() { + let count = 0 + for (let key in this.elements) { + count++ + } + return count + } + + union(secondSet) { + let unioned = this.elements + for (var elem of secondSet.elements) + if (unioned.indexOf(elem) === -1) { + unioned[unioned.length] = elem + } + var unique = unioned.filter(function(element, index, self) { + return index == self.indexOf(element); + }) + return unique + } + + intersect(secondSet) { + let intersected = [] + for (var elem of secondSet.elements) + if (this.elements.indexOf(elem) > 0) { + intersected[intersected.length] = elem + } + var unique = intersected.filter(function(element, index, self) { + return index == self.indexOf(element); + }) + return unique + } + + difference(secondSet) { + let differences = [] + for (var elem of this.elements) + if (secondSet.elements.indexOf(elem) === -1 ) { + differences[differences.length] = elem + } + for (var elem of secondSet.elements) + if (this.elements.indexOf(elem) === -1 ) { + differences[differences.length] = elem + } + var unique = differences.filter(function(element, index, self) { + return index == self.indexOf(element); + }) + return unique + } + + isSubset(secondSet) { + return secondSet.elements.every((elements, index, array) => { + return this.elements.indexOf(elements) !== -1; + }) + } + + clone() { + let newSet = new Set(this.elements) + return newSet.elements + } + +} From 1591475634e0e00cca9d74536c1700f81f783815 Mon Sep 17 00:00:00 2001 From: thamaranth Date: Mon, 30 Jan 2017 14:39:52 -0800 Subject: [PATCH 15/17] added work for several structures --- lib/pQueue.js | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/queue.js | 74 ++++++++++++++++++++++++ lib/set.js | 82 ++++++++++++++++++++++++++ 3 files changed, 312 insertions(+) create mode 100644 lib/pQueue.js create mode 100644 lib/queue.js create mode 100644 lib/set.js diff --git a/lib/pQueue.js b/lib/pQueue.js new file mode 100644 index 0000000..5bfa562 --- /dev/null +++ b/lib/pQueue.js @@ -0,0 +1,156 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var PriorityQueue = function () { + function PriorityQueue() { + var initialValues = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + _classCallCheck(this, PriorityQueue); + + this.elements = initialValues; + } + + _createClass(PriorityQueue, [{ + key: 'enqueue', + value: function enqueue(value, priority) { + this.elements[this.elements.length] = [value, priority]; + } + }, { + key: 'front', + value: function front() { + if (this.elements.length) { + var highest = this.elements[0]; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.elements[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var pair = _step.value; + + if (pair[1] > highest[1]) { + highest = pair; + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return highest; + } + return null; + } + }, { + key: 'back', + value: function back() { + if (this.elements.length) { + var lowest = this.elements[0]; + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = this.elements[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var pair = _step2.value; + + if (pair[1] < lowest[1]) { + lowest = pair; + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return lowest; + } + return null; + } + }, { + key: 'dequeue', + value: function dequeue() { + if (this.elements.length) { + var highest = this.elements[0]; + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = this.elements[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var pair = _step3.value; + + if (pair[1] > highest[1]) { + highest = pair; + } + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + this.elements.splice(this.elements.indexOf(highest), 1); + return highest; + } + return null; + } + }, { + key: 'isEmpty', + value: function isEmpty() { + if (this.elements.length) { + return false; + } + return true; + } + }, { + key: 'length', + value: function length() { + var count = 0; + for (var key in this.elements) { + count++; + } + return count; + } + }]); + + return PriorityQueue; +}(); + +exports.default = PriorityQueue; \ No newline at end of file diff --git a/lib/queue.js b/lib/queue.js new file mode 100644 index 0000000..c9e1d08 --- /dev/null +++ b/lib/queue.js @@ -0,0 +1,74 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Queue = function () { + function Queue() { + var initialValues = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + _classCallCheck(this, Queue); + + this.elements = initialValues; + } + + _createClass(Queue, [{ + key: 'enqueue', + value: function enqueue(value) { + this.elements[this.elements.length] = value; + } + }, { + key: 'dequeue', + value: function dequeue() { + if (this.elements.length === 0) { + return null; + } + var result = this.elements.slice(0, 1); + this.elements.splice(0, 1); + return result; + } + }, { + key: 'front', + value: function front() { + if (this.elements.length) { + return this.elements[0]; + } + + return null; + } + }, { + key: 'back', + value: function back() { + if (this.elements.length) { + return this.elements.slice(-1)[0]; + } + return null; + } + }, { + key: 'isEmpty', + value: function isEmpty() { + if (this.elements.length) { + return false; + } + return true; + } + }, { + key: 'length', + value: function length() { + var count = 0; + for (var key in this.elements) { + count++; + } + return count; + } + }]); + + return Queue; +}(); + +exports.default = Queue; \ No newline at end of file diff --git a/lib/set.js b/lib/set.js new file mode 100644 index 0000000..b92d5a7 --- /dev/null +++ b/lib/set.js @@ -0,0 +1,82 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Set = function () { + function Set() { + var initialValues = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + _classCallCheck(this, Set); + + this.elements = initialValues; + } + + _createClass(Set, [{ + key: "add", + value: function add(value) { + if (this.elements.indexOf(value) === -1) { + this.elements[this.elements.length] = value; + return this.elements; + } + return false; + } + }, { + key: "isEmpty", + value: function isEmpty() { + if (this.elements.length === 0) { + return true; + } + return false; + } + }, { + key: "contains", + value: function contains(value) { + if (this.elements.indexOf(value) > 0) { + return true; + } + return false; + } + }, { + key: "remove", + value: function remove(value) { + if (this.elements.indexOf(value) > 0) { + return this.elements.splice(this.elements.indexOf(value), 1); + } + return "The value to remove does not exist"; + } + }, { + key: "forEach", + value: function forEach(func) { + this.elements = this.elements.map(func); + return this.elements; + } + }, { + key: "size", + value: function size() { + var count = 0; + for (var key in this.elements) { + count++; + } + return count; + } + }, { + key: "union", + value: function union(secondSet) { + openedArr = this.elements.map(secondSet); + if (openedArr.indexOf(secondSet) === -1) { + this.elements[this.elements.length] = secondSet; + return this.elements; + } + } + }]); + + return Set; +}(); + +exports.default = Set; \ No newline at end of file From c7cee07c1592beb2f471b194ef18c0775770f514 Mon Sep 17 00:00:00 2001 From: thamaranth Date: Tue, 31 Jan 2017 15:54:43 -0800 Subject: [PATCH 16/17] finished linkedList --- spec/linkedList_test.js | 124 ++++++++++++++++++++++++++++++++++++++++ spec/set_test.js | 2 - src/linkedList.js | 92 +++++++++++++++++++++++------ 3 files changed, 200 insertions(+), 18 deletions(-) diff --git a/spec/linkedList_test.js b/spec/linkedList_test.js index 96ceb4f..0fdab73 100644 --- a/spec/linkedList_test.js +++ b/spec/linkedList_test.js @@ -25,4 +25,128 @@ describe('Linked List', () => { .to.equal('boo') }) }) + + describe('insertFirst()', () => { + it('Inserts a node (with the provided data) to the head of the list', () => { + const linkedList = new LinkedList() + + expect(() => linkedList.insertFirst('foo')) + .to.alter(() => linkedList.count, { from: 0, to: 1 }) + expect(() => linkedList.insertFirst('boo')) + .to.alter(() => linkedList.count, { from: 1, to: 2 }) + expect(linkedList.getHeadNode().data) + .to.equal('boo') + expect(linkedList.getTailNode().data) + .to.equal('foo') + }) + }) + describe('contains()', () => { + it('Determines whether or not the list contains the provided data', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + + expect(linkedList.contains('foo')) + .to.be.true + expect(linkedList.contains('tap')) + .to.equal(false) + }) + }) + + describe('find()', () => { + it('Determines whether or not the list contains the provided data', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + + expect(linkedList.find('foo')) + .to.deep.equal({ data: 'foo', next: null }) + expect(linkedList.find('tap')) + .to.equal(-1) + }) + }) + + describe('clear()', () => { + it('Clears the list of all nodes/data', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + linkedList.insert('shoo') + + expect(linkedList.clear()) + .to.be.undefined + }) + }) + + describe('removeFirst()', () => { + it('Removes the head node from the list', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + linkedList.insert('shoo') + + expect(linkedList.removeFirst()) + .to.be.undefined + expect(linkedList.getHeadNode().data) + .to.equal('foo') + expect(linkedList.removeFirst()) + .to.be.undefined + expect(linkedList.getHeadNode().data) + .to.equal('shoo') + }) + }) + + describe('remove()', () => { + it('Removes the tail node from the list', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + linkedList.insert('shoo') + + expect(linkedList.remove()) + .to.be.undefined + expect(linkedList.getTailNode().data) + .to.equal('foo') + expect(linkedList.remove()) + .to.be.undefined + expect(linkedList.getTailNode().data) + .to.equal('boo') + }) + }) + + describe('insertAfter()', () => { + it('Inserts a node (with data) after the first node containing "(item)"', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + linkedList.insert('shoo') + + expect(linkedList.insertAfter('shoo', 'moo')) + .to.be.undefined + expect(linkedList.getTailNode().data) + .to.equal('moo') + expect(linkedList.insertAfter('moo', 'doo')) + .to.be.undefined + expect(linkedList.getTailNode().data) + .to.equal('doo') + }) + }) + + describe.only('insertBefore()', () => { + it('Inserts a node (with data) before the first node containing (item)', () => { + const linkedList = new LinkedList() + linkedList.insertFirst('foo') + linkedList.insertFirst('boo') + linkedList.insert('shoo') + + expect(linkedList.insertBefore('shoo', 'moo')) + .to.be.undefined + expect(linkedList.getTailNode().data) + .to.equal('shoo') + expect(linkedList.insertBefore('shoo', 'doo')) + .to.be.undefined + expect(linkedList.getTailNode().data) + .to.equal('shoo') + }) + }) }) diff --git a/spec/set_test.js b/spec/set_test.js index 65a2432..4e227b6 100644 --- a/spec/set_test.js +++ b/spec/set_test.js @@ -157,6 +157,4 @@ describe('Set', () => { .to.deep.equal(['A', 'B', 'C']) }) }) - ->>>>>>> 6b6e0bc454643ca2afa1a9c01e423760549881d0 }) diff --git a/src/linkedList.js b/src/linkedList.js index 3be005c..0b69a71 100644 --- a/src/linkedList.js +++ b/src/linkedList.js @@ -22,16 +22,28 @@ export default class LinkedList { return this.tail } - contains() { + find(item) { + let currentNode = this.head + while (currentNode) { + if (currentNode.data === item) { + return currentNode + } else { + currentNode = currentNode.next + } + } + return -1 } - find() { - + clear() { + this.head = null + this.tail = null + this.count = 0 } insert(item) { const newNode = new Node(item) + if (this.head === null) { this.head = newNode } else { @@ -39,45 +51,93 @@ export default class LinkedList { } this.tail = newNode this.count++ - // if (this.count = 0){ - // this.head = newNode - // this.tail = newNode - // } else { - // this.tail = newNode - // } + return newNode } - insertFirst() { + insertFirst(item) { + const newNode = new Node(item) + + if (this.head) { + newNode.next = this.head + } else { + this.tail = newNode + } + + this.head = newNode + this.count++ + + return newNode } - insertBefore() { + insertBefore(item, data) { + const node = new Node(data) + node.next = this.find(item) + + if (node.next === this.getHeadNode()) { + this.head = node + } else { + let currentNode = this.getHeadNode() + while (currentNode.next !== node.next) { + currentNode = currentNode.next + } + currentNode.next = node + } + this.count++ } - insertAfter() { + insertAfter(item, data) { + const node = new Node(data) + if (this.find(item) === this.getTailNode()) { + this.tail = node + } + node.next = this.find(item).next + this.find(item).next = node + this.count++ } remove() { + if (this.count === 1) { + this.clear() + } else { + let currentNode = this.getHeadNode() + while (currentNode.next.next) { + currentNode = currentNode.next + } + currentNode.next = null + this.count-- + this.tail = currentNode + } } removeFirst() { + if (this.count === 1) { + this.clear() + } else { + this.head = this.getHeadNode().next + this.count-- + } } isEmpty() { - + if(!this.head){ + return null + } else { + return this.data + } } size() { - + return this.count } - clear() { - + contains(item) { + return this.find(item) !== -1 } } From b3d837f021897edb2accf6882a44548da44382c7 Mon Sep 17 00:00:00 2001 From: thamaranth Date: Wed, 1 Feb 2017 11:37:52 -0800 Subject: [PATCH 17/17] finished double linked list --- spec/doubleLinkedList_test.js | 156 ++++++++++++++++++++++++++++++++++ spec/linkedList_test.js | 2 +- src/doubleLinkedList.js | 150 ++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 spec/doubleLinkedList_test.js create mode 100644 src/doubleLinkedList.js diff --git a/spec/doubleLinkedList_test.js b/spec/doubleLinkedList_test.js new file mode 100644 index 0000000..84d0797 --- /dev/null +++ b/spec/doubleLinkedList_test.js @@ -0,0 +1,156 @@ +import chai, { expect } from 'chai' +import chaiChange from 'chai-change' +import DoubleLinkedList from '../src/doubleLinkedList' + +chai.use(chaiChange) + +describe('Double Linked List', () => { + 'use strict' + + it('exists', () => { + expect(DoubleLinkedList).to.be.a('function') + }) + + describe('insert()', () => { + it('Inserts a node (with the provided data) to the tail of the list', () => { + const doubleLinkedList = new DoubleLinkedList() + + expect(() => doubleLinkedList.insert('foo')) + .to.alter(() => doubleLinkedList.count, { from: 0, to: 1 }) + expect(doubleLinkedList.getHeadNode().data) + .to.equal('foo') + expect(() => doubleLinkedList.insert('boo')) + .to.alter(() => doubleLinkedList.count, { from: 1, to: 2 }) + expect(doubleLinkedList.getTailNode().data) + .to.equal('boo') + }) + }) + + describe('insertFirst()', () => { + it('Inserts a node (with the provided data) to the head of the list', () => { + const doubleLinkedList = new DoubleLinkedList() + + expect(() => doubleLinkedList.insertFirst('foo')) + .to.alter(() => doubleLinkedList.count, { from: 0, to: 1 }) + expect(() => doubleLinkedList.insertFirst('boo')) + .to.alter(() => doubleLinkedList.count, { from: 1, to: 2 }) + console.log(doubleLinkedList) + expect(doubleLinkedList.getHeadNode().data) + .to.equal('boo') + expect(doubleLinkedList.getTailNode().data) + .to.equal('foo') + }) + }) + describe('contains()', () => { + it('Determines whether or not the list contains the provided data', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + + expect(doubleLinkedList.contains('foo')) + .to.be.true + expect(doubleLinkedList.contains('tap')) + .to.equal(false) + }) + }) + + describe('find()', () => { + it('Determines whether or not the list contains the provided data', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + doubleLinkedList.insertFirst('shoo') + doubleLinkedList.insertFirst('test') + console.log(doubleLinkedList) + + expect(doubleLinkedList.find('shoo').data) + .to.equal('shoo') + expect(doubleLinkedList.find('tap')) + .to.equal(-1) + }) + }) + + describe('clear()', () => { + it('Clears the list of all nodes/data', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + doubleLinkedList.insert('shoo') + + expect(doubleLinkedList.clear()) + .to.be.undefined + }) + }) + + describe('removeFirst()', () => { + it('Removes the head node from the list', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + doubleLinkedList.insert('shoo') + + expect(doubleLinkedList.removeFirst()) + .to.be.undefined + expect(doubleLinkedList.getHeadNode().data) + .to.equal('foo') + expect(doubleLinkedList.removeFirst()) + .to.be.undefined + expect(doubleLinkedList.getHeadNode().data) + .to.equal('shoo') + }) + }) + + describe('remove()', () => { + it('Removes the tail node from the list', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + doubleLinkedList.insert('shoo') + + expect(doubleLinkedList.remove()) + .to.be.undefined + expect(doubleLinkedList.getTailNode().data) + .to.equal('foo') + expect(doubleLinkedList.remove()) + .to.be.undefined + expect(doubleLinkedList.getTailNode().data) + .to.equal('boo') + }) + }) + + describe('insertAfter()', () => { + it('Inserts a node (with data) after the first node containing "(item)"', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + doubleLinkedList.insert('shoo') + + expect(doubleLinkedList.insertAfter('shoo', 'moo')) + .to.be.undefined + expect(doubleLinkedList.getTailNode().data) + .to.equal('moo') + expect(doubleLinkedList.insertAfter('moo', 'doo')) + .to.be.undefined + expect(doubleLinkedList.getTailNode().data) + .to.equal('doo') + }) + }) + + describe.only('insertBefore()', () => { + it('Inserts a node (with data) before the first node containing (item)', () => { + const doubleLinkedList = new DoubleLinkedList() + doubleLinkedList.insertFirst('foo') + doubleLinkedList.insertFirst('boo') + doubleLinkedList.insert('shoo') + + expect(doubleLinkedList.insertBefore('shoo', 'moo')) + .to.be.undefined + expect(doubleLinkedList.getTailNode().data) + .to.equal('shoo') + expect(doubleLinkedList.insertBefore('shoo', 'doo')) + .to.be.undefined + expect(doubleLinkedList.getTailNode().data) + .to.equal('shoo') + }) + }) +}) diff --git a/spec/linkedList_test.js b/spec/linkedList_test.js index 0fdab73..48219ae 100644 --- a/spec/linkedList_test.js +++ b/spec/linkedList_test.js @@ -132,7 +132,7 @@ describe('Linked List', () => { }) }) - describe.only('insertBefore()', () => { + describe('insertBefore()', () => { it('Inserts a node (with data) before the first node containing (item)', () => { const linkedList = new LinkedList() linkedList.insertFirst('foo') diff --git a/src/doubleLinkedList.js b/src/doubleLinkedList.js new file mode 100644 index 0000000..0c809a1 --- /dev/null +++ b/src/doubleLinkedList.js @@ -0,0 +1,150 @@ +'use strict' + +class Node { + constructor(data) { + this.data = data + this.next = null + this.prev = null + } +} + +export default class DoubleLinkedList { + constructor() { + this.count = 0 + this.head = null + this.tail = null + } + + getHeadNode() { + return this.head + } + + getTailNode() { + return this.tail + } + + + find(item) { + let currentNode = this.head + while (currentNode) { + if (currentNode.data === item) { + return currentNode + } else { + currentNode = currentNode.next + } + } + return -1 + } + + clear() { + this.head = null + this.tail = null + this.count = 0 + } + + insert(item) { + const newNode = new Node(item) + + if (this.head === null) { + this.head = newNode + } else { + this.tail.next = newNode + newNode.prev = this.tail + } + this.tail = newNode + this.count++ + + return newNode + } + + insertFirst(item) { + const newNode = new Node(item) + + if (this.head) { + this.head.prev = newNode + newNode.next = this.head + } else { + this.tail = newNode + } + + this.head = newNode + this.count++ + + return newNode + + } + + insertBefore(item, data) { + const newNode = new Node(data) + newNode.next = this.find(item) + + if (newNode.next === this.head) { + this.head.prev = newNode + this.head = newNode + } else { + let currentNode = this.head + while (currentNode.next !== newNode.next) { + currentNode = currentNode.next + } + newNode.prev = currentNode + currentNode.next = newNode + } + this.count++ + + } + + insertAfter(item, data) { + const newNode = new Node(data) + + if (this.find(item) === this.tail { + newNode.prev = this.tail + this.tail = newNode + } + newNode.next = this.find(item).next + newNode.prev = this.find(item) + this.find(item).next = newNode + this.count++ + + } + + remove() { + if (this.count === 1) { + this.clear() + } else { + let currentNode = this.getHeadNode() + while (currentNode.next.next) { + currentNode = currentNode.next + } + currentNode.next = null + this.count-- + this.tail = currentNode + } + + } + + removeFirst() { + if (this.count === 1) { + this.clear() + } else { + this.head = this.getHeadNode().next + this.count-- + } + + } + + isEmpty() { + if(!this.head){ + return null + } else { + return this.data + } + } + + size() { + return this.count + } + + contains(item) { + return this.find(item) !== -1 + } +}