collection2  v0.6.0
Loading...
Searching...
No Matches
list.hpp
1//
2// リスト
3//
4
5#ifndef _COLLECTION2_LIST_H_
6#define _COLLECTION2_LIST_H_
7
8#include <stddef.h>
9
10#include "common.hpp"
11
12namespace collection2 {
13
20template <typename Element, typename Size = size_t>
21struct Node {
22 // 有効なノードか
23 bool isEnabled = false;
24
25 // 次の要素へのポインタ
26 Node* next = nullptr;
27
28 // 前の要素へのポインタ
29 Node* previous = nullptr;
30
31 // ノードが持つ要素
32 Element element;
33};
34
40template <typename Element, typename Size = size_t>
41class List {
42 private:
46 Node<Element>* const internalData;
47
51 Size internalDataSize;
52
56 Node<Element, Size>* headPtr = nullptr;
57
61 Node<Element, Size>* tailPtr = nullptr;
62
66 Size count = 0;
67
73 Node<Element, Size>* getNewNode() const;
74
75 public:
82 List(Node<Element, Size>* const data, const Size& dataSize);
83
84 List(const List&) = delete;
85 List& operator=(const List&) = delete;
86
87 ~List() = default;
88
95 OperationResult append(const Element& element);
96
104 OperationResult insert(const Size& index, const Element& element);
105
112 OperationResult pop(Element* const element);
113
121 OperationResult remove(const Size& index, Element* const element);
122
131 Element* get(const Size& index);
132
139 return headPtr;
140 }
141
148 return tailPtr;
149 }
150
156 Size capacity() const {
157 return internalDataSize;
158 }
159
165 Size amount() const {
166 return count;
167 }
168};
169
170template <typename Element, typename Size>
171List<Element, Size>::List(Node<Element, Size>* const data, const Size& dataSize) : internalData(data), internalDataSize(dataSize){};
172
173template <typename Element, typename Size>
175 for (Size i = 0; i < internalDataSize; i++) {
176 if (internalData[i].isEnabled) {
177 continue;
178 }
179
180 // 見つかったらノードを初期化して返す
181 internalData[i].isEnabled = true;
182 internalData[i].next = nullptr;
183 internalData[i].previous = nullptr;
184 return &(internalData[i]);
185 }
186 return nullptr;
187}
188
189template <typename Element, typename Size>
191 // 新しいノードを取得し、値を設定
192 auto* newNode = getNewNode();
193 if (newNode == nullptr) {
194 return OperationResult::Overflow;
195 }
196 newNode->element = element;
197
198 // 先頭の値がないならそこにセットして戻る
199 if (headPtr == nullptr) {
200 headPtr = newNode;
201 tailPtr = newNode;
202 count++;
203 return OperationResult::Success;
204 }
205
206 // tailに接続
207 tailPtr->next = newNode;
208 newNode->previous = tailPtr;
209 tailPtr = newNode;
210 count++;
211
212 return OperationResult::Success;
213}
214
215template <typename Element, typename Size>
216OperationResult List<Element, Size>::insert(const Size& index, const Element& element) {
217 // 新しいノードを取得し、値を設定
218 auto* newNode = getNewNode();
219 if (newNode == nullptr) {
220 return OperationResult::Overflow;
221 }
222 newNode->element = element;
223
224 // 先頭の値がないならそこにセットして戻る
225 if (headPtr == nullptr) {
226 headPtr = newNode;
227 tailPtr = newNode;
228 count++;
229 return OperationResult::Success;
230 }
231
232 // 先頭への追加の場合、現在のheadが新しいノードのnextとなる
233 if (index == 0) {
234 newNode->next = headPtr;
235 headPtr = newNode;
236 count++;
237 return OperationResult::Success;
238 }
239
240 // 先頭から最大index回nextを辿り、追加位置の直前のノードを取得
241 auto* previousNode = headPtr;
242 Size currentIndex = 0;
243 while (previousNode->next != nullptr && currentIndex < index - 1) {
244 previousNode = previousNode->next;
245 currentIndex++;
246 }
247
248 // 接続
249 if (previousNode->next == nullptr) {
250 // 前のノードの次がnull -> リスト終端への追加
251 tailPtr = newNode;
252 } else {
253 // 前のノードの次が存在 -> リスト途中への追加
254 previousNode->next->previous = newNode;
255 }
256 newNode->next = previousNode->next;
257
258 newNode->previous = previousNode;
259 previousNode->next = newNode;
260
261 count++;
262
263 return OperationResult::Success;
264}
265
266template <typename Element, typename Size>
268 if (tailPtr == nullptr) {
269 return OperationResult::Empty;
270 }
271
272 // 対象ノードはtailから参照できる
273 auto* targetNode = tailPtr;
274
275 // tailの位置に格納されている情報を渡す
276 if (element != nullptr) {
277 *element = targetNode->element;
278 }
279
280 // tailを一つ戻す
281 tailPtr = targetNode->previous;
282 if (tailPtr == nullptr) {
283 // tailがnullになった=リストが空になった
284 headPtr = nullptr;
285 }
286
287 // ノードを無効化する
288 targetNode->isEnabled = false;
289 targetNode->next = nullptr;
290 targetNode->previous = nullptr;
291
292 count--;
293
294 return OperationResult::Success;
295}
296
297template <typename Element, typename Size>
298OperationResult List<Element, Size>::remove(const Size& index, Element* const element) {
299 if (headPtr == nullptr) {
300 return OperationResult::Empty;
301 }
302
303 // 先頭のノードを削除する場合
304 if (index == 0) {
305 // 先頭を一つ先にずらす
306 auto* targetNode = headPtr;
307 headPtr = targetNode->next;
308 if (headPtr == nullptr) {
309 // headがnullになった=リストが空になった
310 tailPtr = nullptr;
311 }
312
313 // ノードに格納されている情報を渡す
314 if (element != nullptr) {
315 *element = targetNode->element;
316 }
317
318 // 要素を無効化
319 targetNode->isEnabled = false;
320 targetNode->next = nullptr;
321 targetNode->previous = nullptr;
322
323 count--;
324
325 return OperationResult::Success;
326 }
327
328 // 先頭からindex回、最大で配列の末尾までnextを辿り、削除位置のノードを取得
329 auto* targetNode = headPtr;
330 Size currentIndex = 0;
331 while (targetNode->next != nullptr && currentIndex < index) {
332 targetNode = targetNode->next;
333 currentIndex++;
334 }
335
336 // ノードに格納されている情報を渡す
337 if (element != nullptr) {
338 *element = targetNode->element;
339 }
340
341 // 前後を再接続
342 if (targetNode->next == nullptr) {
343 // 前のノードの次がnull -> リスト終端の削除
344 tailPtr = targetNode->previous;
345 } else {
346 // 前のノードの次が存在 -> リスト中間の削除
347 targetNode->next->previous = targetNode->previous;
348 }
349 targetNode->previous->next = targetNode->next;
350
351 // ノードを無効化
352 targetNode->isEnabled = false;
353 targetNode->next = nullptr;
354 targetNode->previous = nullptr;
355
356 count--;
357
358 return OperationResult::Success;
359}
360
361template <typename Element, typename Size>
362Element* List<Element, Size>::get(const Size& index) {
363 if (headPtr == nullptr) {
364 return nullptr;
365 }
366
367 // 先頭からindex回、最大で配列の末尾までnextを辿る
368 auto* node = headPtr;
369 Size currentIndex = 0;
370 while (node->next != nullptr && currentIndex < index) {
371 node = node->next;
372 currentIndex++;
373 }
374
375 // インデックス範囲外
376 if (currentIndex < index) {
377 return nullptr;
378 }
379
380 return &(node->element);
381}
382
383} // namespace collection2
384
385#endif
リスト
Definition: list.hpp:41
Node< Element > * head() const
リスト先頭へのポインタを取得
Definition: list.hpp:138
OperationResult append(const Element &element)
リストの末尾にデータを追加
Definition: list.hpp:190
OperationResult remove(const Size &index, Element *const element)
リスト内の任意の位置にあるデータを削除し、取り出す
Definition: list.hpp:298
Size amount() const
現在リスト内にあるデータ数を返す
Definition: list.hpp:165
Node< Element > * tail() const
リスト末尾へのポインタを取得
Definition: list.hpp:147
Element * get(const Size &index)
リスト内の要素を参照する
Definition: list.hpp:362
List(Node< Element, Size > *const data, const Size &dataSize)
内部データを扱う領域とそのサイズを指定してリストを初期化
Definition: list.hpp:171
OperationResult pop(Element *const element)
リスト末尾のデータを削除し、取り出す
Definition: list.hpp:267
Size capacity() const
リストの全体長を返す
Definition: list.hpp:156
OperationResult insert(const Size &index, const Element &element)
リスト内の任意の位置にデータを追加
Definition: list.hpp:216
OperationResult
コレクション操作結果
Definition: common.hpp:14
リストの一要素を表す構造体
Definition: list.hpp:21