-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlist.ts
More file actions
151 lines (132 loc) · 4.09 KB
/
list.ts
File metadata and controls
151 lines (132 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { NodeItem } from './node';
export class List<T> {
private _headNode: NodeItem<T> | null;
private _tailNode: NodeItem<T> | null;
private _length: number;
constructor() {
this._headNode = null;
this._tailNode = null;
this._length = 0;
}
get headNode(): NodeItem<T> | null {
return this._headNode;
}
set headNode(node: NodeItem<T> | null) {
this._headNode = node;
}
get tailNode(): NodeItem<T> | null {
return this._tailNode;
}
set tailNode(node: NodeItem<T> | null) {
this._tailNode = node;
}
get head(): T | null {
if (this.headNode != null) {
return this.headNode.data
}
return null;
}
// Returns a new list with all elements of the original list except the first.
get tail() {
const clonedList = this.cloneRecursion(this.headNode);
const headNode = clonedList.headNode;
const newHeadNode = headNode ? headNode.nextNode : null;
clonedList.headNode = newHeadNode;
clonedList.length--;
return clonedList;
}
get length() {
return this._length;
}
set length(n: number) {
this._length = n;
}
elementAt(n: number, node: NodeItem<T> | null = this.headNode): T | null {
if (node === null) {
return null;
}
if (n === 0) {
return node.data
}
return this.elementAt(n - 1, node.nextNode);
}
reverse(): List<T> {
if (this.headNode) {
// return this.prependList(this.headNode, new List<T>());
return new List<T>().reverseList(this.headNode);
}
return this;
}
// Reversing a list without cons operation
prependList(node: NodeItem<T> | null, list: List<T>): List<T> {
if (node === null) {
return list;
}
// Tail call optimized
return this.prependList(node.nextNode, list.cons(node.data));
}
// Reversing a list using cons operation
reverseList(node: NodeItem<T> | null): List<T> {
if (node === null) {
return this;
}
return this.cons(node.data).reverseList(node.nextNode);
}
// Drops n nodes from the list means doing the tail operation n times
drop(n: number): List<T> {
if (n === 0) {
return this;
}
return this.tail.drop(n - 1);
}
cons(data: T | null): List<T> {
if (data === null) {
return this;
}
// Create a new Node
const newNode = new NodeItem<T>(data);
const clonedList = this.cloneRecursion(this.headNode);
// Prepend this data
newNode.nextNode = clonedList.headNode;
clonedList.headNode = newNode;
clonedList.length++;
return clonedList;
}
// Iterative version of clone
private clone(): List<T> {
// Returns a clone of the current list
const currentList = this;
const newList = new List<T>();
let nextNode = this.headNode;
newList.headNode = null;
let prevNode: NodeItem<T> | null = null;
while (nextNode) {
const newNode = new NodeItem<T>(nextNode.data);
if (prevNode) {
prevNode.nextNode = newNode;
} else {
newList.headNode = newNode;
}
prevNode = newNode;
nextNode = nextNode.nextNode;
}
return newList;
}
// Recursive version of clone
private cloneRecursion(node: NodeItem<T> | null, list: List<T> = new List<T>(), prevNode: NodeItem<T> | null = null): List<T> {
if (node === null) {
return list;
}
const newNode = new NodeItem<T>(node.data);
const newList = new List<T>();
newList.length = list.length + 1;
newList.headNode = list.headNode;
newList.tailNode = newNode;
if (prevNode) {
prevNode.nextNode = newNode;
} else {
newList.headNode = newNode;
}
return this.cloneRecursion(node.nextNode, newList, newNode);
}
}