Olá Isabella,
Estou supondo que você se refere aos templates de classe da biblioteca padrão do C++.
std::array representa um arranjo alocado na pilha, cujo tamanho nunca muda. std::array fornece acesso aleatório, o que significa que você consegue acessar qualquer elemento em tempo constante, ou seja, O(1). Os elementos de um std::array são armazenados contiguamente em memória, ou seja, os elementos são dispostos um após o outro em sequência. Inserção e remoção de um elemento no/do meio não é O(1). Exemplo:
std::array<int, 5> meu_array = {10, 20, 30, 40, 50};
std::cout << meu_array[2] << std::endl; // imprime 30
std::vector representa um arranjo alocado na heap, cujo tamanho pode mudar. std::vector também fornece acesso aleatório e também garante que os elementos são armazenados contiguamente em memória. Inserção e remoção de um elemento no/do meio também não é O(1). Exemplo:
std::vector<int> meu_vector = {10, 20, 30, 40, 50};
meu_vector.push_back(60); // inserir 60 no final
std::cout << meu_vector[5] << std::endl; // imprime 60
std::deque representa uma fila em que você pode inserir e da qual você pode remover elementos tanto no/do início quanto no/do final em O(1). std::deque também fornece acesso aleatório mas não garante que os elementos estarão armazenados contiguamente em memória. Inserção e remoção de um elemento no/do meio também não é O(1). Exemplo:
std::deque<int> meu_deque = {10, 20, 30, 40, 50};
meu_deque.push_back(60); // inserir 60 no final
meu_deque.push_front(5); // inserir 5 no inicio
std::cout << meu_deque.back() << std::endl; // imprime 60
meu_deque.pop_back(); // remove o 60;
std::cout << meu_deque.back() << std::endl; // imprime o novo final: 50
std::cout << meu_deque.front() << std::endl; // imprime 5
meu_deque.pop_front(); // remove o 5
std::cout << meu_deque.front() << std::endl; // imprime o novo inicio: 10
std::list representa uma lista duplamente encadeada em que você consegue inserir e remover elementos em/de qualquer posição da lista para a qual você já possui um iterador, em O(1). std::list não fornece acesso aleatório e também não garante que os elementos serão armazenados contiguamente em memória. Exemplo:
std::list<int> meu_list = {10, 20, 30, 40, 50};
std::cout << *(++meu_list.begin()) << std::endl; // imprimimos o segundo elemento: 20
std::list<int>::iterator it = ++meu_list.begin(); // obtemos um iterador para o segundo elemento
meu_list.erase(it); // removemos o segundo elemento em O(1)
std::cout << *(++meu_list.begin()) << std::endl; // imprimimos o novo segundo elemento: 30
A diferença básica entre essas estruturas de dados é quais operações que podem ser feitas nelas rapidamente. Quando desenvolvemos um programa que vai rodar em um computador real, temos que lidar com desempenho, ou seja, o quão rápido o programa será na prática, e dependendo das necessidades do programa podemos escolher uma estrutura de dados que maximize o desempenho.
Espero ter ajudado. Diga se algo não ficou claro.