# JavaScript Data Structure and Algorithms One-way Chain List

Catalog

JavaScript Data Structure and Algorithms (6) One-way Chain List

Recognition Chain List

Chain lists and arrays

Common operations in a chain table

Encapsulation of one-way chain table

# JavaScript Data Structure and Algorithms (6) One-way Chain List

## Recognition Chain List

### Chain lists and arrays

Chain lists, like arrays, can be used to store a series of elements, but they are implemented entirely differently.

array

• Storing multiple elements, arrays (or lists) may be the most common data structure.

• Almost every programming language has a default implementation array structure that provides a convenient [] syntax to access array elements.

• Array drawbacks:

The creation of an array requires a continuous memory space (a block of memory) and is fixed in size, which needs to be expanded when the current array cannot meet capacity requirements. (Typically, a larger array is requested, such as twice, and then the elements in the original array are copied over.)

Inserting data at the beginning or middle of an array is costly and requires a large number of element shifts.

• Storing multiple elements, another option is to use a chain table.

• Unlike arrays, elements in a chain table do not have to be contiguous in memory.

• Each element of a chain table consists of a node that stores the element itself and a reference to the next element (referred to in some languages as a pointer).

Memory space does not have to be continuous to make full use of the computer's memory for flexible dynamic memory management.

Chain lists do not have to be sized when they are created, and sizes can extend indefinitely.

Chain lists can be O(1) time-complex and much more efficient than arrays when inserting and deleting data.

• Chain list shortcomings:

When accessing an element at any location, you need to start from scratch. (You cannot skip the first element to access any element)

Elements cannot be accessed directly from subscript values; they need to be accessed from scratch one by one until the corresponding element is found.

Although it is easy to get to the next node, it is difficult to get back to the previous node.

A one-way chain list is similar to a train with a locomotive that connects a node with passengers, and this node connects the next node, and so on.

• Train structure of chain list

• Data structure of linked list

The head property points to the first node of the chain table.
The last node in the list points to null. When there is no node in the list, the head er points directly to null.

• Add data to train structure

### Common operations in a chain table

• append(element) adds a new item to the end of the list.
• insert(position, element) inserts a new item to a specific location in the list of chains.
• get(position) Gets the element of the corresponding position.
• indexOf(element) returns the index of an element in a chain table. If the element is not in the chain table, it returns -1.
• update(position, element) Modifies the element of a location.
• removeAt(position) Removes an item from a specific location in the list of chains.
• remove(element) Removes an item from the list of chains.
• isEmpty() Returns true if the list does not contain any elements, false if the length of the list is greater than 0.
• size() returns the number of elements contained in the chain table, similar to the length property of an array.
• toString() Since chain list items use the Node class, you need to override the default toString method inherited from the JavaScript object so that it only outputs the value of the element.

### Encapsulation of one-way chain table

Create a one-way chain table class

Create a one-way chain table class LinkedList, add basic properties, and then gradually implement the common methods of one-way chain table.

```class LinkedList {
// Initial list length is 0
length = 0;

// The initial header is null, and the header points to the first node in the chain table

// Internal Class (Node in Chain List)
Node = class {
data;
next = null;
constructor(data) {
this.data = data;
}
};
}```

Implementing the append() method

code implementation

```// append() appends data to the end of the list
append(data) {

// 1. Create a new node
const newNode = new this.Node(data);

// 2. Append new nodes
if (this.length === 0) {

// When the list length is 0, that is, when there is only the head

} else {
// Add a new node at the end when the chain length is greater than 0

// When currentNode.next is not empty,
// Find the last node in sequence, when the next node is null
while (currentNode.next !== null) {
currentNode = currentNode.next;
}

// The next of the last node points to the new node
currentNode.next = newNode;
}

// 3. Chain list length + 1 after appending new nodes
this.length++;

}```

Process Mapping

• First, point the currentNode to the first node.

• Make the currentNode point to the last node through the while loop, and finally make the last node point to the new node, newNode, through the currentNode.next = newNode.

Code Testing

```const linkedList = new LinkedList();
// Test append method

Implement the toString() method

code implementation

```toString() {
let result = '';

// Traverse all nodes and stitch them into strings until they are null
while (currentNode) {
result += currentNode.data + ' ';
currentNode = currentNode.next;
}

return result;
}```

Code Testing

```// Test the toString method

Implement insert() method

code implementation

```// insert() inserts a node at a specified location
insert(position, data) {
// position New Inserted Node Location
// position = 0 means the first node after the new insert
// position = 1 indicates the second node after the new insertion, and so on

// 1. position cannot be less than 0 or greater than the length of the list.
if (position < 0 || position > this.length) return false;

// 2. Create a new node
const newNode = new this.Node(data);

// 3. Insert Node
if (position === 0) { // position = 0
// Let the next of the new node point to the original first node, head

} else { // 0 < position <= length case

// Initialize some variables
let previousNode = null; // The previous node of head is null
let index = 0; // index of head is 0

// Traverse between 0 and position, continuously updating currentNode and previousNode
// Until you find the location you want to insert
while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}

// Insert a new node between the current node and the previous node of the current node, that is, their change points to
newNode.next = currentNode;
previousNode.next = newNode;
}

this.length++;
return newNode;
}```

Code Testing

```// Test insert method
console.log(linkedList.toString()); //--> 123 AA 456 BB CC```

Implement the getData() method

Gets the data at the specified location.

code implementation

```getData(position) {
// 1. position Judgment Over Bounds
if (position < 0 || position >= this.length) return null;

// 2. Get data for the specified position node
let index = 0;

while (index++ < position) {
currentNode = currentNode.next;
}
return currentNode.data;
}```

Code Testing

```// Test getData method

Implementing the indexOf() method

indexOf(data) returns the index of the specified data, or -1 if not.

code implementation

```indexOf(data) {

let index = 0;

while (currentNode) {
if (currentNode.data === data) {
return index;
}
currentNode = currentNode.next;
index++;
}

return -1;
}```

Code Testing

```// Testing indexOf method

Implement the update() method

update(position, data) modifies the data of the specified location node.

code implementation

```update(position, data) {
// Cross-border judgment is required when position ing is involved
// 1. position Judgment Over Bounds
if (position < 0 || position >= this.length) return false;

// 2. Traverse through the loop to find the node that specified the position
let index = 0;
while (index++ < position) {
currentNode = currentNode.next;
}

// 3. Modify node data
currentNode.data = data;

return currentNode;
}```

Code Testing

```// Testing the update method
console.log(linkedList.toString()); //--> 12345 AA 456 BB CC
console.log(linkedList.toString()); //--> 12345 54321 456 BB CC```

Implement the removeAt() method

removeAt(position) Deletes a node at a specified location.

code implementation

```removeAt(position) {
// 1. position Judgment Over Bounds
if (position < 0 || position >= this.length) return null;

// 2. Delete the specified position node
if (position === 0) {
// position = 0

} else {
// Position > 0
// Loop through to find the node of the specified position and assign it to currentNode

let previousNode = null;
let index = 0;

while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}

// Clever enough, having the next of the previous node point to the next of the current node is equivalent to deleting the current node.
previousNode.next = currentNode.next;
}

// 3. Update Chain List Length-1
this.length--;

return currentNode;
}```

Code Testing

```// Test the removeAt s method
console.log(linkedList.toString()); //--> 12345 54321 456 CC```

Implement the remove() method

remove(data) Deletes the node where the specified data resides.

code implementation

```remove(data) {
this.removeAt(this.indexOf(data));
}```

Code Testing

```// Test the remove method

Implement the isEmpty() method

isEmpty() determines if the chain list is empty.

code implementation

```isEmpty() {
return this.length === 0;
}```

Code Testing

```// Testing isEmpty method

Implement size() method

size() Gets the length of the chain table.

code implementation

```size() {
return this.length;
}```

Code Testing

```// Test the size method

Full implementation

```class LinkedList {
// Initial list length is 0
length = 0;

// The initial header is null, and the header points to the first node in the chain table

// Internal Class (Node in Chain List)
Node = class {
data;
next = null;

constructor(data) {
this.data = data;
}
};

// ----------------------------------//

// append() appends data to the end of the list
append(data) {
// 1. Create a new node
const newNode = new this.Node(data);

// 2. Append new nodes
if (this.length === 0) {
// When the list length is 0, that is, when there is only the head
} else {
// Add a new node at the end when the chain length is greater than 0

// When currentNode.next is not empty,
// Find the last node in sequence, when the next node is null
while (currentNode.next !== null) {
currentNode = currentNode.next;
}

// The next of the last node points to the new node
currentNode.next = newNode;
}

// 3. Chain list length + 1 after appending new nodes
this.length++;
}

// insert() inserts a node at a specified location
insert(position, data) {
// position New Inserted Node Location
// position = 0 means the first node after the new insert
// position = 1 indicates the second node after the new insertion, and so on

// 1. position cannot be less than 0 or greater than the length of the list.
if (position < 0 || position > this.length) return false;

// 2. Create a new node
const newNode = new this.Node(data);

// 3. Insert Node
if (position === 0) {
// position = 0
// Let the next of the new node point to the original first node, head

} else {
// 0 < position <= length case

// Initialize some variables
let previousNode = null; // The previous node of head is null
let index = 0; // index of head is 0

// Traverse between 0 and position, continuously updating currentNode and previousNode
// Until you find the location you want to insert
while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}

// Insert a new node between the current node and the previous node of the current node, that is, their change points to
newNode.next = currentNode;
previousNode.next = newNode;
}

this.length++;
return newNode;
}

// getData() Gets the data at the specified location
getData(position) {
// 1. position Judgment Over Bounds
if (position < 0 || position >= this.length) return null;

// 2. Get data for the specified position node
let index = 0;

while (index++ < position) {
currentNode = currentNode.next;
}

return currentNode.data;
}

// indexOf() returns the index of the specified data, or -1 if not.
indexOf(data) {
let index = 0;

while (currentNode) {
if (currentNode.data === data) {
return index;
}
currentNode = currentNode.next;
index++;
}

return -1;
}

// update() Modify the data of the specified location node
update(position, data) {
// Cross-border judgment is required when position ing is involved
// 1. position Judgment Over Bounds
if (position < 0 || position >= this.length) return false;

// 2. Traverse through the loop to find the node that specified the position
let index = 0;
while (index++ < position) {
currentNode = currentNode.next;
}

// 3. Modify node data
currentNode.data = data;

return currentNode;
}

// removeAt() deletes a node at a specified location
removeAt(position) {
// 1. position Judgment Over Bounds
if (position < 0 || position >= this.length) return null;

// 2. Delete the specified position node
if (position === 0) {
// position = 0
} else {
// Position > 0
// Loop through to find the node of the specified position and assign it to currentNode

let previousNode = null;
let index = 0;

while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}

// Clever enough, having the next of the previous node point to the next of the current node is equivalent to deleting the current node.
previousNode.next = currentNode.next;
}

// 3. Update Chain List Length-1
this.length--;

return currentNode;
}

// remove() deletes a node of the specified data
remove(data) {
this.removeAt(this.indexOf(data));
}

// isEmpty() determines if the list of chains is empty
isEmpty() {
return this.length === 0;
}

// size() Gets the length of the chain table
size() {
return this.length;
}

// toString() chain table data returned as a string
toString() {