動的配列
動的配列とは
- 動的配列(C++の配列、実行中にサイズの変更が可能)
⇔固定長配列(C言語の配列、実行開始時からサイズの変更が不可能) - 配列と同様の操作が可能。また、データの追加、削除が可能
- 配列と同様にデータは先頭から末尾まで順にメモリに格納されており、
連続したデータである為、末尾(最後の次)以外へのデータの追加、削除は負荷が大きい
用途 : オブジェクトを管理するリストなど
vector(C++)
Example.cpp
#include <iostream>
#include <vector>
#include <format>
int main(void)
{
// 宣言・定義
// std::vector<型> 変数名;
std::vector<int> iVector = { 1, 2, 3, 4, 5 };
std::cout << std::format("確保しているメモリの容量 : {}", iVector.capacity()) << std::endl;
std::cout << std::format("格納している要素の数 : {}", iVector.size()) << std::endl;
// 要素の追加(末尾)
// std::vector.push_back(値);
iVector.push_back(6);
std::cout << std::format("確保しているメモリの容量 : {}", iVector.capacity()) << std::endl;
std::cout << std::format("格納している要素の数 : {}", iVector.size()) << std::endl;
// 要素の追加(任意)
// std::vector.insert(iterator.position, 値);
iVector.insert(iVector.begin(), -1);
iVector.insert(iVector.end(), 7);
std::cout << std::format("確保しているメモリの容量 : {}", iVector.capacity()) << std::endl;
std::cout << std::format("格納している要素の数 : {}", iVector.size()) << std::endl;
// (※)イテレータの定義
// std::vector<型>::iterator 変数名;
std::vector<int>::iterator itr = iVector.begin();
itr += 4;
iVector.insert(itr, 100);
std::cout << std::format("確保しているメモリの容量 : {}", iVector.capacity()) << std::endl;
std::cout << std::format("格納している要素の数 : {}", iVector.size()) << std::endl;
// Range-based for loop(C++11以上)での出力
for (int i : iVector)
{
std::cout << i << std::endl;
}
// 要素の削除(末尾)
// std::vector.pop_back();
std::cout << std::format("{} を削除しました", iVector.back()) << std::endl;
iVector.pop_back();
// 要素の削除(任意)
// std::vector.erase(iterator.position)
itr = iVector.begin();
itr += 4;
std::cout << std::format("{} を削除しました", *itr) << std::endl;
iVector.erase(itr);
// 要素の削除(条件)
// std::vector.erase(iterator.position)
// remove_if()の戻り値はiterator.positionを返す
std::cout << "3 以下の値を削除しました" << std::endl;
iVector.erase
(
remove_if(iVector.begin(), iVector.end(), [](int& i) { return i <= 3; }),
iVector.end()
);
// 要素の全削除
// std::vector.clear()
// std::vector.shrink_to_fit()はcapacity = sizeにする
iVector.clear();
iVector.shrink_to_fit();
std::cout << std::format("確保しているメモリの容量 : {}", iVector.capacity()) << std::endl;
std::cout << std::format("格納している要素の数 : {}", iVector.size()) << std::endl;
// イテレータの操作での出力
for (std::vector<int>::iterator itr = iVector.begin(); itr != iVector.end(); itr++)
{
std::cout << *itr << std::endl;
}
return 0;
}
remove_if
remove_if(削除を開始する位置を示すイテレータ, 削除を終了する位置を示すイテレータ, ラムダ式);
->条件を満たす要素をコンテナの後ろに移動し、新しい終端イテレータを返す
List(C#)
Example.cs
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 宣言・定義
// List<型> 変数名 = new List<型>();
List<int> iList = new List<int> { 1, 2, 3, 4, 5 };
Console.WriteLine($"確保しているメモリの容量 : {iList.Capacity}");
Console.WriteLine($"格納している要素の数 : {iList.Count}");
// 要素の追加(末尾)
// List.Add(値);
iList.Add(6);
Console.WriteLine($"確保しているメモリの容量 : {iList.Capacity}");
Console.WriteLine($"格納している要素の数 : {iList.Count}");
// 要素の追加(任意)
// List.insert(index, 値);
iList.Insert(iList.GetEnumerator().Current, -1);
iList.Insert(iList.Count - 1, 7);
Console.WriteLine($"確保しているメモリの容量 : {iList.Capacity}");
Console.WriteLine($"格納している要素の数 : {iList.Count}");
// foreachでの出力
foreach (int i in iList)
{
Console.WriteLine(i);
}
// 要素の削除(末尾)
// List.RemoveAt(List.Count - 1);
Console.WriteLine($"{iList[iList.Count - 1]}を削除しました");
iList.RemoveAt(iList.Count - 1);
// 要素の削除(条件)
// List.RemoveAll(ラムダ式)
Console.WriteLine("3以下の値を削除しました");
iList.RemoveAll(i => i <= 3);
// 要素の全削除
// List.clear()
iList.Clear();
Console.WriteLine($"確保しているメモリの容量 : {iList.Capacity}");
Console.WriteLine($"格納している要素の数 : {iList.Count}");
// イテレータの操作での出力
itr = iList.GetEnumerator();
while (itr.MoveNext())
{
Console.WriteLine(itr.Current);
}
}
}
連結リスト
連結リストとは
- 自身の前後のアドレスのみを知る構造
- 配列とは違いバラバラな位置にデータが格納されているため、
配列のような操作(ランダムアクセス
)は不可能 - 任意の位置への追加、削除に優れている特徴を持つ
用途 : 生成・削除が頻繁に行われるオブジェクト(シューティングゲームの弾など)の管理
list(C++)
Example.cpp
#include <iostream>
#include <list>
#include <format>
int main(void)
{
// 宣言・定義
// std::list<型> 変数名;
std::list<int> iList = { 1, 2, 3, 4, 5 };
std::cout << std::format("格納している要素の数 : {}", iList.size()) << std::endl;
// 要素の追加(末尾)
// std::list.push_back(値)
iList.push_back(6);
std::cout << std::format("格納している要素の数 : {}", iList.size()) << std::endl;
// 要素の追加(先頭)
// std::list.push_front(値)
iList.push_front(-1);
std::cout << std::format("格納している要素の数 : {}", iList.size()) << std::endl;
// 要素の追加(任意)
// std::list.insert(iterator.position, 値);
iList.insert(iList.begin(), -2);
iList.insert(iList.end(), 7);
std::cout << std::format("格納している要素の数 : {}", iList.size()) << std::endl;
// (※)イテレータの定義
// std::list<型>::iterator 変数名;
std::list<int>::iterator itr = iList.begin();
advance(itr, 4);
iList.insert(itr, 100);
std::cout << std::format("格納している要素の数 : {}", iList.size()) << std::endl;
// Range-based for loop(C++11以上)での出力
for (int i : iList)
{
std::cout << i << std::endl;
}
// 要素の削除(末尾)
// std::list.pop_back();
std::cout << std::format("{} を削除しました", iList.back()) << std::endl;
iList.pop_back();
// 要素の削除(先頭)
// std::list.pop_front();
std::cout << std::format("{} を削除しました", iList.front()) << std::endl;
iList.pop_front();
// 要素の削除(任意)
// std::list.erase(iterator.position)
itr = iList.begin();
advance(itr, 4);
std::cout << std::format("{} を削除しました", *itr) << std::endl;
iList.erase(itr);
// 要素の削除(条件)
// std::list.erase(iterator.position)
// remove_if()の戻り値はiterator.positionを返す
std::cout << "3 以下の値を削除しました" << std::endl;
iList.erase
(
remove_if(iList.begin(), iList.end(), [](int& i) { return i <= 3; }),
iList.end()
);
// 要素の全削除
// std::list.clear()
iList.clear();
std::cout << std::format("格納している要素の数 : {}", iList.size()) << std::endl;
// イテレータの操作での出力
for (int i : iList)
{
std::cout << i << std::endl;
}
return 0;
}
LinkedList(C#)
Example.cs
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 宣言・定義
// LinkedList<型> 変数名 = new List<型>();
LinkedList<int> iLinkedList = new LinkedList<int>(new int[] { 1, 2, 3, 4, 5 });
Console.WriteLine($"格納している要素の数 : {iLinkedList.Count}");
// 要素の追加(末尾)
// LinkedList.AddLast(値);
iLinkedList.AddLast(6);
Console.WriteLine($"格納している要素の数 : {iLinkedList.Count}");
// 要素の追加(先頭)
// LinkedList.AddFirst(値);
iLinkedList.AddFirst(-1);
Console.WriteLine($"格納している要素の数 : {iLinkedList.Count}");
// 要素の追加(任意)
// LinkedList.AddBefore(index, indexの要素の前に追加する値);
// LinkedList.AddAfter(index, indexの要素の後に追加する値);
iLinkedList.AddBefore(iLinkedList.First, -2);
iLinkedList.AddAfter(iLinkedList.Last, 7);
Console.WriteLine($"格納している要素の数 : {iLinkedList.Count}");
// (※)イテレータの定義
// LinkedListNode<型> 変数名;
LinkedListNode<int> itr = iLinkedList.First;
for (int i = 0; i < 4; i++) { itr = itr.Next; }
iLinkedList.AddAfter(itr, 100);
Console.WriteLine($"格納している要素の数 : {iLinkedList.Count}");
// foreachでの出力
foreach (int i in iLinkedList)
{
Console.WriteLine(i);
}
// 要素の削除(末尾)
// LinkedList.RemoveLast();
Console.WriteLine($"{iLinkedList.Last.Value}を削除しました");
iLinkedList.RemoveLast();
// 要素の削除(先頭)
// LinkedList.RemoveFirst();
Console.WriteLine($"{iLinkedList.First.Value}を削除しました");
iLinkedList.RemoveFirst();
// 要素の削除(任意)
// LinkedList.Remove(itr);
itr = iLinkedList.First;
for (int i = 0; i < 4; i++) { itr = itr.Next; }
Console.WriteLine($"{itr.Value}を削除しました");
iLinkedList.Remove(itr);
// 要素の削除(条件)
// List.RemoveAll(ラムダ式)
Console.WriteLine("3以下の値を削除しました");
while (itr != null)
{
if (itr.Value <= 3)
{
iLinkedList.Remove(itr);
}
itr = itr.Next;
}
// 要素の全削除
// LinkedList.clear()
iLinkedList.Clear();
Console.WriteLine($"格納している要素の数 : {iLinkedList.Count}");
// イテレータの操作での出力
itr = iLinkedList.First;
while (itr != null)
{
Console.WriteLine(itr.Value);
itr = itr.Next;
}
}
}
連想配列
連想配列とは
- pair型(Key(鍵)とValue(値))によって管理されるデータの構造
- KeyとValueには別々の型が入る
- 二次元配列に似た使用感
用途 : エンティティの管理(IDと情報など)、オブジェクト属性(体力、攻撃力など)の管理など
map(C++)
Example.cpp
#include <iostream>
#include <map>
#include <string>
#include <format>
int main(void)
{
// 宣言
// std::map<keyとなる型, valueとなる型> 変数名;
std::map<std::string, int> iMap;
// 要素の追加(二次元配列方式)
iMap["A"] = 0;
iMap["B"] = 10;
iMap["C"] = 20;
std::cout << std::format("格納している要素の数 : {}", iMap.size()) << std::endl;
// 要素の追加(std::make_pair<型, 型>())
// std::map.insert(std::make_pair<型, 型>(key, value));
iMap.insert(std::make_pair<std::string, int>("あ", 100));
std::cout << std::format("格納している要素の数 : {}", iMap.size()) << std::endl;
// 要素の追加(make_pair())
// std::map.insert(std::make_pair(key, value));
// ※ (型)値 はC言語のキャスト
iMap.insert(std::make_pair((std::string)"い", 100));
std::cout << std::format("格納している要素の数 : {}", iMap.size()) << std::endl;
// 要素の追加(make_pair())
// std::map.insert(std::make_pair(key, value));
// ※ static_cast<std::string>値 はC++のキャスト
iMap.insert(std::make_pair(static_cast<std::string>("う"), 100));
std::cout << std::format("格納している要素の数 : {}", iMap.size()) << std::endl;
// 要素の追加(emplace)
// std::map.emplace(key, value);
iMap.emplace("え", 100);
std::cout << std::format("格納している要素の数 : {}", iMap.size()) << std::endl;
// Range-based for loop(C++11以上)での出力
for (std::pair<std::string, int> pair : iMap)
{
std::cout << std::format("Key : {}, Value : {}", pair.first, pair.second) << std::endl;
}
// 要素の削除
// std::map.erase(key);
std::cout << std::format("Key : え, Value : {} を削除しました", iMap["え"]) << std::endl;
iMap.erase("え");
// 勝手に新規作成しやがる場合
// iMap.at(key)を使うとエラーを出せる
int tmp = iMap["エラーにならない1"];
std::cout << tmp << std::endl;
// 新規作成->削除
iMap.erase("エラーにならない2");
// 要素の全削除
// std::map.clear()
iMap.clear();
std::cout << std::format("格納している要素の数 : {}", iMap.size()) << std::endl;
// イテレータの操作での出力
for (std::map<std::string, int>::iterator itr = iMap.begin(); itr != iMap.end(); itr++)
{
std::cout << std::format("Key : {}, Value : {}", itr->first, itr->second) << std::endl;
}
return 0;
}
insertとemplaceの違い
insert : キーと値のペアのコピーまたはムーブを行う
emplace : キーと値のペアの直接構築を行う
Dictionary(C#)
Example.cs
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 宣言
// Dictionary<keyとなる型, valueとなる型> 変数名 = new Dictionary<同型, 同型>();
Dictionary<string, int> iMap = new Dictionary<string, int>();
// 要素の追加(二次元配列方式)
iMap["A"] = 0;
iMap["B"] = 10;
iMap["C"] = 20;
Console.WriteLine($"格納している要素の数 : {iMap.Count}");
// 要素の追加(Add)
// Dictionary.Add(key, value);
iMap.Add("あ", 100);
Console.WriteLine($"格納している要素の数 : {iMap.Count}");
// foreachでの出力
foreach (KeyValuePair<string, int> pair in iMap)
{
Console.WriteLine($"Key : {pair.Key}, Value : {pair.Value}");
}
// 要素の削除
// Dictionary.Remove(key);
iMap.Remove("あ");
Console.WriteLine($"格納している要素の数 : {iMap.Count}");
// 要素の全削除
// Dictionary.Clear()
iMap.Clear();
Console.WriteLine($"格納している要素の数 : {iMap.Count}");
}
}
(※)イテレータ
イテレータとは抽象化されたポインタのこと。
用途 : コンテナクラスの操作
先頭はコンテナクラス型.begin()、末尾は**コンテナクラス型.end()**で取得可能
※末尾とは最後の要素の次
*itrはイテレータが指し示す要素の値を取得できる
最後に
一応、UnityC#でのテスト(Console->Debug.Log)を行っていますが、
本家C#との違いがあればご指摘お願いします。