mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-05 08:16:50 +08:00
merge: Improvement on singly circular linkedList (#981)
* Auto-update DIRECTORY.md * Update and rename SingleCircularLinkedList.js.js to SinglyCircularLinkedList.js * Test Case creation for SinglyCircularLinkedList * Update SinglyCircularLinkedList.js * Update SinglyCircularLinkedList.test.js * Update SinglyCircularLinkedList.js Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
This commit is contained in:
@ -1,88 +0,0 @@
|
||||
class Node {
|
||||
constructor (data, next = null) {
|
||||
this.data = data
|
||||
this.next = next
|
||||
}
|
||||
}
|
||||
|
||||
class SinglyCircularLinkedList {
|
||||
constructor () {
|
||||
this.head = null
|
||||
this.size = 0
|
||||
}
|
||||
|
||||
insert (data) {
|
||||
const node = new Node(data)
|
||||
|
||||
if (!this.head) {
|
||||
node.next = node
|
||||
this.head = node
|
||||
this.size++
|
||||
} else {
|
||||
node.next = this.head
|
||||
|
||||
let current = this.head
|
||||
|
||||
while (current.next.data !== this.head.data) {
|
||||
current = current.next
|
||||
}
|
||||
|
||||
current.next = node
|
||||
this.size++
|
||||
}
|
||||
}
|
||||
|
||||
insertAt (index, data) {
|
||||
const node = new Node(data)
|
||||
|
||||
if (index < 0 || index > this.size) return
|
||||
|
||||
if (index === 0) {
|
||||
this.head = node
|
||||
this.size = 1
|
||||
return
|
||||
}
|
||||
|
||||
let previous
|
||||
let count = 0
|
||||
let current = this.head
|
||||
|
||||
while (count < index) {
|
||||
previous = current
|
||||
current = current.next
|
||||
count++
|
||||
}
|
||||
|
||||
node.next = current
|
||||
previous.next = node
|
||||
this.size++
|
||||
}
|
||||
|
||||
remove () {
|
||||
if (!this.head) return
|
||||
|
||||
let prev
|
||||
let current = this.head
|
||||
|
||||
while (current.next !== this.head) {
|
||||
prev = current
|
||||
current = current.next
|
||||
}
|
||||
|
||||
prev.next = this.head
|
||||
this.size--
|
||||
}
|
||||
|
||||
printData (output = value => console.log(value)) {
|
||||
let count = 0
|
||||
let current = this.head
|
||||
|
||||
while (current !== null && count < this.size) {
|
||||
output(current.data)
|
||||
current = current.next
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { SinglyCircularLinkedList }
|
157
Data-Structures/Linked-List/SinglyCircularLinkedList.js
Normal file
157
Data-Structures/Linked-List/SinglyCircularLinkedList.js
Normal file
@ -0,0 +1,157 @@
|
||||
// Methods - size, head, isEmpty, getElementAt, addAtFirst, add, clean, insertAt, remove, removeData, printData, get, clear
|
||||
import { Node } from './SinglyLinkedList.js'
|
||||
|
||||
class SinglyCircularLinkedList {
|
||||
constructor () {
|
||||
this.headNode = null
|
||||
this.length = 0
|
||||
}
|
||||
|
||||
// Get size of the linkedList
|
||||
size = () => this.length
|
||||
// Get the headNode data
|
||||
head = () => this.headNode?.data || null
|
||||
// Check if the linkedList is empty
|
||||
isEmpty = () => this.length === 0
|
||||
|
||||
// initiate the node and index
|
||||
initiateNodeAndIndex () {
|
||||
return { currentNode: this.headNode, currentIndex: 0 }
|
||||
}
|
||||
|
||||
// get the data specific to an index
|
||||
getElementAt (index) {
|
||||
if (this.length !== 0 && index >= 0 && index <= this.length) {
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
for (let i = 0; i < index && currentNode !== null; i++) {
|
||||
currentNode = currentNode.next
|
||||
}
|
||||
return currentNode
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
// Add the element in the first position
|
||||
addAtFirst (data) {
|
||||
const node = new Node(data)
|
||||
node.next = this.headNode
|
||||
this.headNode = node
|
||||
this.length++
|
||||
return this.length
|
||||
}
|
||||
|
||||
// Add any data to the end of the linkedList
|
||||
add (data) {
|
||||
if (!this.headNode) { return this.addAtFirst(data) }
|
||||
const node = new Node(data)
|
||||
// Getting the last node
|
||||
const currentNode = this.getElementAt(this.length - 1)
|
||||
currentNode.next = node
|
||||
node.next = this.headNode
|
||||
this.length++
|
||||
return this.length
|
||||
}
|
||||
|
||||
// insert data at a specific position
|
||||
insertAt (index, data) {
|
||||
if (index === 0) return this.addAtFirst(data)
|
||||
if (index === this.length) return this.add(data)
|
||||
if (index < 0 || index > this.length) throw new RangeError(`Index is out of range max ${this.length}`)
|
||||
const node = new Node(data)
|
||||
const previousNode = this.getElementAt(index - 1)
|
||||
node.next = previousNode.next
|
||||
previousNode.next = node
|
||||
this.length++
|
||||
return this.length
|
||||
}
|
||||
|
||||
// find the first index of the data
|
||||
indexOf (data) {
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
// initializing currentIndex as -1
|
||||
let currentIndex = -1
|
||||
while (currentNode) {
|
||||
if (currentNode.data === data) {
|
||||
return currentIndex + 1
|
||||
}
|
||||
currentIndex++
|
||||
currentNode = currentNode.next
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// remove the data from the end of the list
|
||||
remove () {
|
||||
if (this.isEmpty()) return null
|
||||
const secondLastNode = this.getElementAt(this.length - 2)
|
||||
const removedNode = secondLastNode.next
|
||||
secondLastNode.next = this.headNode
|
||||
this.length--
|
||||
return removedNode.data || null
|
||||
}
|
||||
|
||||
// remove the data from the first of the list
|
||||
removeFirst () {
|
||||
if (this.isEmpty()) return null
|
||||
const removedNode = this.headNode
|
||||
if (this.length === 1) {
|
||||
this.clear()
|
||||
return removedNode.data
|
||||
}
|
||||
const lastNode = this.getElementAt(this.length - 1)
|
||||
this.headNode = this.headNode.next
|
||||
lastNode.next = this.headNode
|
||||
this.length--
|
||||
return removedNode.data || null
|
||||
}
|
||||
|
||||
// remove the data from the index
|
||||
removeAt (index) {
|
||||
if (this.isEmpty()) return null
|
||||
if (index === 0) return this.removeFirst()
|
||||
if (index === this.length) return this.remove()
|
||||
if (index < 0 && index > this.length) return null
|
||||
const previousNode = this.getElementAt(index - 1)
|
||||
const currentNode = previousNode.next
|
||||
previousNode.next = currentNode.next
|
||||
this.length--
|
||||
return currentNode.data || null
|
||||
}
|
||||
|
||||
// remove if the data is present
|
||||
removeData (data) {
|
||||
if (this.isEmpty()) return null
|
||||
const index = this.indexOf(data)
|
||||
return this.removeAt(index)
|
||||
}
|
||||
|
||||
// logs the data
|
||||
printData (output = value => console.log(value)) {
|
||||
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
|
||||
|
||||
while (currentNode !== null && currentIndex < this.length) {
|
||||
output(currentNode.data)
|
||||
currentNode = currentNode.next
|
||||
currentIndex++
|
||||
}
|
||||
}
|
||||
|
||||
// get the data from the linkedList
|
||||
get () {
|
||||
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
|
||||
const list = []
|
||||
while (currentNode !== null && currentIndex < this.length) {
|
||||
list.push(currentNode.data)
|
||||
currentNode = currentNode.next
|
||||
currentIndex++
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
clear () {
|
||||
this.headNode = null
|
||||
this.length = 0
|
||||
}
|
||||
}
|
||||
|
||||
export { SinglyCircularLinkedList }
|
@ -0,0 +1,147 @@
|
||||
import { SinglyCircularLinkedList } from '../SinglyCircularLinkedList'
|
||||
|
||||
describe('SinglyCircularLinkedList', () => {
|
||||
let list
|
||||
beforeEach(() => {
|
||||
list = new SinglyCircularLinkedList()
|
||||
})
|
||||
it('Check get', () => {
|
||||
expect(list.get()).toEqual([])
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.get()).toEqual([1])
|
||||
expect(list.add(5)).toEqual(2)
|
||||
expect(list.get()).toEqual([1, 5])
|
||||
})
|
||||
|
||||
it('Check size', () => {
|
||||
expect(list.size()).toEqual(0)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.size()).toEqual(2)
|
||||
})
|
||||
|
||||
it('Check head', () => {
|
||||
expect(list.head()).toEqual(null)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.head()).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.head()).toEqual(1)
|
||||
expect(list.addAtFirst(100)).toEqual(3)
|
||||
expect(list.head()).toEqual(100)
|
||||
expect(list.insertAt(0, 500)).toEqual(4)
|
||||
expect(list.head()).toEqual(500)
|
||||
list.clear()
|
||||
expect(list.head()).toEqual(null)
|
||||
})
|
||||
|
||||
it('Check isEmpty', () => {
|
||||
expect(list.isEmpty()).toEqual(true)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.isEmpty()).toEqual(false)
|
||||
})
|
||||
|
||||
it('Check getElementAt', () => {
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
|
||||
expect(list.getElementAt(1).data).toEqual(200)
|
||||
expect(list.getElementAt(3).data).toEqual(500)
|
||||
})
|
||||
|
||||
it('Check addAtFirst', () => {
|
||||
list.add(1)
|
||||
list.add(5)
|
||||
list.add(7)
|
||||
list.add(9)
|
||||
list.add(0)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0])
|
||||
list.addAtFirst(100)
|
||||
expect(list.get()).toEqual([100, 1, 5, 7, 9, 0])
|
||||
})
|
||||
|
||||
it('Check add', () => {
|
||||
list.add(1)
|
||||
list.add(5)
|
||||
list.add(7)
|
||||
list.add(9)
|
||||
list.add(0)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0])
|
||||
list.add(100)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0, 100])
|
||||
})
|
||||
|
||||
it('Check insertAt', () => {
|
||||
expect(list.insertAt(0, 100)).toEqual(1)
|
||||
expect(list.get()).toEqual([100])
|
||||
expect(list.insertAt(0, 200)).toEqual(2)
|
||||
expect(list.get()).toEqual([200, 100])
|
||||
expect(list.insertAt(2, 300)).toEqual(3)
|
||||
expect(list.get()).toEqual([200, 100, 300])
|
||||
})
|
||||
|
||||
it('Checks indexOf', () => {
|
||||
expect(list.indexOf(200)).toEqual(-1)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.indexOf(200)).toEqual(1)
|
||||
})
|
||||
|
||||
it('Check remove', () => {
|
||||
expect(list.remove()).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.remove()
|
||||
expect(removedData).toEqual(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500])
|
||||
})
|
||||
|
||||
it('Check removeFirst', () => {
|
||||
expect(list.removeFirst()).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeFirst()
|
||||
expect(removedData).toEqual(100)
|
||||
expect(list.get()).toEqual([200, 300, 500, 900])
|
||||
})
|
||||
|
||||
it('Check removeAt', () => {
|
||||
expect(list.removeAt(1)).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeAt(2)
|
||||
expect(removedData).toEqual(300)
|
||||
expect(list.get()).toEqual([100, 200, 500, 900])
|
||||
})
|
||||
|
||||
it('Check removeData', () => {
|
||||
expect(list.removeData(100)).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeData(200)
|
||||
expect(removedData).toEqual(200)
|
||||
expect(list.get()).toEqual([100, 300, 500, 900])
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user