fix: Bug fix for 'resize', 'insertAt', and 'deleteAt'.

This commit is contained in:
Revone 2023-11-17 18:44:14 +08:00
parent e7be7b559d
commit d761e79e4d
4 changed files with 171 additions and 43 deletions

View file

@ -808,7 +808,7 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', '
[//]: # (No deletion!!! Start of Replace Section)
<div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>deque</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>36.67</td><td>27.27</td><td>0.00</td></tr><tr><td>1,000,000 shift</td><td>35.78</td><td>27.95</td><td>0.00</td></tr><tr><td>1,000,000 push</td><td>35.96</td><td>27.81</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>39.29</td><td>25.45</td><td>0.00</td></tr><tr><td>1,000,000 push & shift</td><td>39.46</td><td>25.34</td><td>0.00</td></tr><tr><td>1,000,000 unshift & shift</td><td>36.93</td><td>27.08</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>70.01</td><td>14.28</td><td>0.01</td></tr><tr><td>1,000,000 CPT push</td><td>14.52</td><td>68.86</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>72.74</td><td>13.75</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>74.59</td><td>13.41</td><td>0.01</td></tr><tr><td>1,000,000 unshift & shift</td><td>72.73</td><td>13.75</td><td>0.01</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

View file

@ -308,22 +308,19 @@ export class Deque<E = any> {
return false;
}
// If inserted at the head
if (index === 0) {
this.unshift(element);
return true;
}
//If inserted at the end
if (index === this.size) {
this.push(element);
return true;
}
// Intermediate insertion requires processing of arrays
this._ensureCapacityForInsert();
const actualIndex = this.headOffset + index;
for (let i = this.tailOffset; i > actualIndex; i--) {
const actualIndex = this._headOffset + index;
for (let i = this._tailOffset; i > actualIndex; i--) {
this._elements[i] = this._elements[i - 1];
}
this._elements[actualIndex] = element;
@ -352,17 +349,17 @@ export class Deque<E = any> {
return undefined;
}
const actualIndex = this.headOffset + index;
const actualIndex = this._headOffset + index;
const removedElement = this._elements[actualIndex];
for (let i = actualIndex; i < this.tailOffset - 1; i++) {
for (let i = actualIndex; i < this._tailOffset - 1; i++) {
this._elements[i] = this._elements[i + 1];
}
this._tailOffset--;
this._elements[this._tailOffset] = undefined as unknown as E; // Clear reference to the last element
return removedElement;
}
/**
* Time Complexity: O(n) - May need to scan the entire deque.
* Space Complexity: O(1) - No extra space required.
@ -607,16 +604,17 @@ export class Deque<E = any> {
protected _resize() {
const newCapacity = this.capacity * 2;
const newElements = new Array(newCapacity);
const newHeadOffset = Math.floor((newCapacity - this.size) / 2);
const size = this.size;
const newHeadOffset = Math.floor((newCapacity - size) / 2);
for (let i = 0; i < this.size; i++) {
newElements[newHeadOffset + i] = this._elements[this.headOffset + i];
for (let i = 0; i < size; i++) {
newElements[newHeadOffset + i] = this._elements[this._headOffset + i];
}
this._elements = newElements;
this._capacity = newCapacity;
this._headOffset = newHeadOffset;
this._tailOffset = newHeadOffset + this.size;
this._tailOffset = newHeadOffset + size;
}
/**

View file

@ -9,49 +9,33 @@ const { LINEAR } = magnitude;
suite.add(`${LINEAR.toLocaleString()} push`, () => {
const deque = new Deque<number>();
for (let i = 0; i < LINEAR; i++) {
deque.push(i);
}
for (let i = 0; i < LINEAR; i++) deque.push(i);
});
if (isCompetitor) {
suite.add(`${LINEAR.toLocaleString()} CPT push`, () => {
const deque = new CDeque<number>();
for (let i = 0; i < LINEAR; i++) {
deque.pushBack(i);
}
const _deque = new CDeque<number>();
for (let i = 0; i < LINEAR; i++) _deque.pushBack(i);
});
}
suite.add(`${LINEAR.toLocaleString()} shift`, () => {
const deque = new Deque<number>();
for (let i = 0; i < LINEAR; i++) {
deque.push(i);
deque.shift();
}
});
suite.add(`${LINEAR.toLocaleString()} push`, () => {
const list = new Deque<number>();
for (let i = 0; i < LINEAR; i++) {
list.push(i);
}
});
suite.add(`${LINEAR.toLocaleString()} push & pop`, () => {
const list = new Deque<number>();
const _deque = new Deque<number>();
for (let i = 0; i < LINEAR; i++) list.push(i);
for (let i = 0; i < LINEAR; i++) list.pop();
for (let i = 0; i < LINEAR; i++) _deque.push(i);
for (let i = 0; i < LINEAR; i++) _deque.pop();
});
suite.add(`${LINEAR.toLocaleString()} push & shift`, () => {
const list = new Deque<number>();
const _deque = new Deque<number>();
for (let i = 0; i < LINEAR; i++) list.push(i);
for (let i = 0; i < LINEAR; i++) list.shift();
for (let i = 0; i < LINEAR; i++) _deque.push(i);
for (let i = 0; i < LINEAR; i++) _deque.shift();
});
suite.add(`${LINEAR.toLocaleString()} unshift & shift`, () => {
const list = new Deque<number>();
const _deque = new Deque<number>();
for (let i = 0; i < LINEAR; i++) list.unshift(i);
for (let i = 0; i < LINEAR; i++) list.shift();
for (let i = 0; i < LINEAR; i++) _deque.unshift(i);
for (let i = 0; i < LINEAR; i++) _deque.shift();
});

View file

@ -272,3 +272,149 @@ describe('ObjectDeque', () => {
expect(deque.getLast()).toBe(3);
});
});
describe('Deque', () => {
let deque: Deque;
beforeEach(() => {
deque = new Deque();
});
test('initializes with default capacity', () => {
expect(deque.capacity).toBe(10);
});
test('initializes with given capacity', () => {
const customDeque = new Deque(20);
expect(customDeque.capacity).toBe(20);
});
test('is initially empty', () => {
expect(deque.isEmpty()).toBe(true);
});
test('pushes and pops elements', () => {
deque.push(1);
deque.push(2);
expect(deque.pop()).toBe(2);
expect(deque.pop()).toBe(1);
expect(deque.pop()).toBeUndefined();
});
test('unshifts and shifts elements', () => {
deque.unshift(1);
deque.unshift(2);
expect(deque.shift()).toBe(2);
expect(deque.shift()).toBe(1);
expect(deque.shift()).toBeUndefined();
});
test('correctly reports size', () => {
expect(deque.size).toBe(0);
deque.push(1);
deque.push(2);
expect(deque.size).toBe(2);
});
test('gets first and last elements', () => {
deque.push(1);
deque.push(2);
deque.push(3);
expect(deque.getFirst()).toBe(1);
expect(deque.getLast()).toBe(3);
});
test('handles resizing automatically', () => {
for (let i = 0; i < 12; i++) {
deque.push(i);
}
expect(deque.size).toBe(12);
expect(deque.capacity).toBeGreaterThan(10);
});
test('converts to array', () => {
deque.push(1);
deque.push(2);
deque.push(3);
expect(deque.toArray()).toEqual([1, 2, 3]);
});
test('clears the deque', () => {
deque.push(1);
deque.push(2);
deque.clear();
expect(deque.isEmpty()).toBe(true);
});
test('inserts and deletes at specific index', () => {
deque.push(1);
deque.push(3);
deque.insertAt(1, 2);
expect(deque.toArray()).toEqual([1, 2, 3]);
expect(deque.deleteAt(1)).toBe(2);
expect(deque.toArray()).toEqual([1, 3]);
});
test('finds elements with a callback', () => {
deque.push(1);
deque.push(2);
deque.push(3);
expect(deque.find(el => el > 1)).toBe(2);
});
test('performs forEach operation', () => {
deque.push(1);
deque.push(2);
let sum = 0;
deque.forEach(el => { sum += el; });
expect(sum).toBe(3);
});
test('maps to a new deque', () => {
deque.push(1);
deque.push(2);
const newDeque = deque.map(el => el * el);
expect(newDeque.toArray()).toEqual([1, 4]);
});
test('filters elements', () => {
deque.push(1);
deque.push(2);
deque.push(3);
const newDeque = deque.filter(el => el % 2 === 0);
expect(newDeque.toArray()).toEqual([2]);
});
test('reduces elements', () => {
deque.push(1);
deque.push(2);
deque.push(3);
const sum = deque.reduce((acc, el) => acc + el, 0);
expect(sum).toBe(6);
});
test('reverses elements', () => {
deque.push(1);
deque.push(2);
deque.push(3);
deque.reverse();
expect(deque.toArray()).toEqual([3, 2, 1]);
});
test('gets element at a specific index', () => {
deque.push(1);
deque.push(2);
deque.push(3);
expect(deque.getAt(1)).toBe(2);
expect(deque.getAt(5)).toBeUndefined();
});
test('finds the index of an element', () => {
deque.push(1);
deque.push(2);
deque.push(3);
expect(deque.indexOf(2)).toBe(1);
expect(deque.indexOf(4)).toBe(-1);
});
});