-
Notifications
You must be signed in to change notification settings - Fork 292
/
ArrayList.cs
175 lines (143 loc) · 4.26 KB
/
ArrayList.cs
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Advanced.Algorithms.DataStructures.Foundation;
/// <summary>
/// A self expanding array implementation.
/// </summary>
/// <typeparam name="T">The datatype of this ArrayList.</typeparam>
public class ArrayList<T> : IEnumerable<T>
{
private readonly int initialArraySize;
private T[] array;
private int arraySize;
/// <summary>
/// Time complexity: O(1) if initial is empty otherwise O(n).
/// </summary>
/// <param name="initalArraySize">The initial array size.</param>
/// <param name="initial">Initial values if any.</param>
public ArrayList(int initalArraySize = 2, IEnumerable<T> initial = null)
{
if (initalArraySize < 2) throw new Exception("Initial array size must be greater than 1");
initialArraySize = initalArraySize;
arraySize = initalArraySize;
array = new T[arraySize];
if (initial == null) return;
foreach (var item in initial) Add(item);
}
/// <summary>
/// Time complexity: O(1) if initial is empty otherwise O(n).
/// </summary>
/// <param name="initial">Initial values if any.</param>
public ArrayList(IEnumerable<T> initial)
: this(2, initial)
{
}
public int Length { get; private set; }
/// <summary>
/// Indexed access to array.
/// Time complexity: O(1).
/// </summary>
/// <param name="index">The index to write or read.</param>
public T this[int index]
{
get => ItemAt(index);
set => SetItem(index, value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return array.Take(Length).GetEnumerator();
}
private T ItemAt(int i)
{
if (i >= Length)
throw new Exception("Index exeeds array size");
return array[i];
}
/// <summary>
/// Add a new item to this array list.
/// Time complexity: O(1) amortized.
/// </summary>
public void Add(T item)
{
Grow();
array[Length] = item;
Length++;
}
/// <summary>
/// Insert given item at specified index.
/// Time complexity: O(1) amortized.
/// </summary>
/// <param name="index">
/// The index to insert at.
/// <param>
/// <param name="item">The item to insert.</param>
public void InsertAt(int index, T item)
{
Grow();
Shift(index);
array[index] = item;
Length++;
}
/// <summary>
/// Shift the position of elements right by one starting at this index.
/// Creates a blank field at index.
/// </summary>
private void Shift(int index)
{
Array.Copy(array, index, array, index + 1, Length - index);
}
/// <summary>
/// Clears the array.
/// Time complexity: O(1).
/// </summary>
public void Clear()
{
arraySize = initialArraySize;
array = new T[arraySize];
Length = 0;
}
private void SetItem(int i, T item)
{
if (i >= Length)
throw new Exception("Index exeeds array size");
array[i] = item;
}
/// <summary>
/// Remove the item at given index.
/// Time complexity: O(1) amortized.
/// </summary>
/// <param name="i">The index to remove at.</param>
public void RemoveAt(int i)
{
if (i >= Length)
throw new Exception("Index exeeds array size");
//shift elements
for (var j = i; j < arraySize - 1; j++) array[j] = array[j + 1];
Length--;
Shrink();
}
private void Grow()
{
if (Length != arraySize) return;
//increase array size exponentially on demand
arraySize *= 2;
var biggerArray = new T[arraySize];
Array.Copy(array, 0, biggerArray, 0, Length);
array = biggerArray;
}
private void Shrink()
{
if (Length != arraySize / 2 || arraySize == initialArraySize) return;
//reduce array by half
arraySize /= 2;
var smallerArray = new T[arraySize];
Array.Copy(array, 0, smallerArray, 0, Length);
array = smallerArray;
}
}