1.リストクラスの概要
- リストの最下層は、先頭ノードを持つ双方向の循環リンクリストを使用しているため、その特徴は次のとおりです。
- 他のシーケンシャルコンテナと比較して、任意の位置での挿入と削除がより効率的です
- 要素のランダムアクセスはサポートされていません
- 要素を見つける時間の複雑さO(n)
2.一般的なインターフェースを一覧表示します
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main()
{
list<int> l1; // 空的构造
list<int> l2(4, 5); // 4个元素值为100
list<int> l3(l2.begin(), l2.end()); // 迭代器构造
list<int> l4(l3); // 拷贝构造
// 用数组构造
int arr[] = {
1,2,3,4,5 };
list<int> l5(arr, arr + sizeof(arr) / sizeof(arr[0]));
// 迭代器
for (auto it = l5.begin(); it != l5.end(); ++it)
cout << *it << " ";
cout << endl;
// 范围for遍历,要实现范围for遍历,应该在容器中增加begin()、end()还有迭代器比较方法
for (auto& e : l5)
cout << e << " ";
cout << endl;
// 容量
l5.empty(); // 判空
l5.size(); // 返回list 有效元素
// 元素访问
l5.front(); // 返回首元素
l5.back(); // 返回尾元素
l5.push_back(9); // 尾插9
l5.push_front(8); // 头插8
l5.pop_back(); // 尾删
l5.pop_front(); // 头删
l5.insert(l5.end(), 20); // 在尾部插入20
l5.insert(l5.begin(), 2, 3); // 插入2个3
l5.erase(--l5.end()); // 尾部删除
auto it = find(l5.begin(), l5.end(), 5); // 查找元素5返回迭代器
l5.clear(); // 清空
return 0;
}
第三に、イテレータの認識と失敗
- イテレータに関する認識:
- コンセプト:コンテナーの実装の詳細を公開せずに、コンテナー内のデータをトラバースするために使用されるデザインパターンです。
- 機能:これは、STLの6つの主要コンポーネントの1つであり、コンテナーとアルゴリズム間のリンクです。アルゴリズムの一般化は、データ型やデータ構造とは関係のないイテレーターを介して使用する必要があります。
- エッセンス:元の生態学的指標または元の生態学的指標のカプセル化
- イテレータをカプセル化するために提供する必要のあるメソッド:
- コンストラクター:オブジェクトと要素を組み合わせるイテレーターを作成します
- ポインタを追加するための同様の操作:operator *()、operator->()
- イテレータの移動:operator ++()、operator-()、operator ++(int)、operator-(int)
- イテレータの比較:operator!=()、operator ==()
- コンテナにイテレータを追加します。
- エイリアス:イテレータ
- begin()、end()インターフェースを追加します
リストのイテレータは元のポインタではなく、ポインタのカプセル化です。これは、イテレータが次のノードに到達できる必要があるためです。
根本的な原因:リンクリストの最下層は連続したスペースではなく、カプセル化されていますポインタフィールドによってリンクされているノード。
- イテレータの失敗に関する認識:基になるポインタが指すスペースが解放され、継続して使用するとプログラムがクラッシュします
- ベクトルでのイテレータの失敗:挿入/削除/展開
- リスト内のイテレータは無効です。削除にのみ表示され、削除されたノードのイテレータにのみ影響し、他のイテレータには影響しません。
第四に、シミュレーション実施リスト
#include <iostream>
using namespace std;
namespace my_list
{
template <class T>
struct ListNode
{
ListNode(const T& val = T())
: val_(val)
, pre_(nullptr)
, next_(nullptr)
{
}
T val_;
ListNode* pre_;
ListNode* next_;
};
template <class T>
struct ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T> Self;
ListIterator(Node* node = nullptr)
:_pNode(node)
{
}
T& operator*()
{
return _pNode->val_;
}
T* operator->()
{
return &(operator*());
}
Self& operator++() // 前置++
{
_pNode = _pNode->next_;
return *this;
}
Self operator++(int) // 后置++
{
Self temp(_pNode);
_pNode = _pNode->next_;
return temp;
}
Self& operator--() // 前置--
{
_pNode = _pNode->pre_;
return *this;
}
Self operator--(int) // 后置--
{
Self temp(_pNode);
_pNode = _pNode->pre_;
return temp;
}
bool operator!=(const Self& it)const
{
return _pNode != it._pNode;
}
bool operator==(const Self& it)const
{
return _pNode == it._pNode;
}
Node* _pNode;
};
template <class T>
class list
{
typedef ListNode<T> Node;
public:
typedef ListIterator<T> iterator;
list()
{
CreateHead();
}
list(size_t n, const T& data = T())
{
CreateHead();
for(int i = 0; i < n; ++i)
push_back(data);
}
//template <class Iterator>
list(int* first, int* last) // 迭代器构造必须采用模板,因为不同容器的迭代器实现可能不同
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
list(const list<T>& node)
{
CreateHead();
Node* cur = node.head_->next_;
while (cur != node.head_)
{
push_back(cur->val_);
cur = cur->next_;
}
}
~list()
{
Clear();
delete head_;
head_ = nullptr;
}
list<T>& operator=(list<T> node)
{
swap(head_, node.head_);
return *this;
}
iterator begin()
{
return iterator(head_->next_);
}
iterator end()
{
return iterator(head_);
}
size_t size()const
{
size_t count = 0;
Node* cur = head_->next_;
while (cur != head_)
{
cur = cur->next_;
count++;
}
return count;
}
bool empty()const
{
return head_->next_ == head_;
}
void resize(size_t n, const T& data = T())
{
size_t oldsize = size();
if (n > oldsize)
{
for (size_t i = oldsize; i < n; ++i)
{
push_back(data);
}
}
else
{
for (size_t i = n; i < oldsize; ++i)
{
pop_back();
}
}
}
void push_back(const T& data)
{
insert(end(), data);
}
void pop_back()
{
erase(--end());
}
void push_front(const T& data)
{
insert(begin(), data);
}
void pop_front()
{
erase(begin());
}
iterator insert(iterator pos, const T& data)
{
Node* node = new Node(data);
Node* posNode = pos._pNode;
node->pre_ = posNode->pre_;
node->next_ = posNode;
posNode->pre_->next_ = node;
posNode->pre_ = node;
return iterator(node);
}
iterator erase(iterator pos)
{
if (pos == end())
return pos;
Node* node = pos._pNode;
Node* pRet = node->next_;
node->pre_->next_ = node->next_;
node->next_->pre_ = node->pre_;
delete node;
node = nullptr;
return iterator(pRet);
}
iterator erase(iterator begin, iterator end)
{
while (begin != end)
{
begin = erase(begin);
}
return begin;
}
void Clear()
{
erase(begin(), end());
}
private:
void CreateHead()
{
head_ = new Node;
head_->pre_ = head_;
head_->next_ = head_;
}
private:
Node* head_;
};
}
void Test1()
{
my_list::list<int> l1;
my_list::list<int> l2(10, 5);
my_list::list<int> l3(l1);
int array[] = {
1,2,3,4,5 };
my_list::list<int> l4{
array, array + sizeof(array) / sizeof(array[0]) };
//auto it = l2.begin();
my_list::ListIterator<int> it = l4.begin();
while (it != l4.end())
{
cout << *it << " ";
it++;
}
cout << endl;
// 如果想要让容器支持范围for循环,则必须实现begin/end的方法,以及迭代器++操作
for (auto e : l2)
cout << e << " ";
cout << endl;
}
void Test2()
{
my_list::list<int> L;
L.push_back(1);
L.push_back(2);
L.push_back(3);
L.push_back(4);
L.push_back(5);
cout << L.size() << endl;
L.resize(10, 6);
for (auto e : L)
cout << e << " ";
cout << endl;
L.resize(4);
for (auto e : L)
cout << e << " ";
cout << endl;
L.push_front(0);
for (auto e : L)
cout << e << " ";
cout << endl;
L.pop_front();
for (auto e : L)
cout << e << " ";
cout << endl;
L.erase(L.begin());
for (auto e : L)
cout << e << " ";
cout << endl;
L.Clear();
if (L.empty())
{
cout << "ok" << endl;
}
}
int main()
{
// 迭代器是对原生态指针的封装
Test1();
return 0;
}
5、ベクトルとリストの違い
類似性:どちらもSTLによって提供されるシリアルコンテナであり、std名前空間に含まれています
ベクター | リスト | |
---|---|---|
基礎となる構造 | 動的に型指定されたシーケンステーブル | ヘッドノードを使用した双方向の循環リンクリスト |
ランダムアクセス | サポート、アクセス要素の時間計算量O(1) | サポートされていません。アクセス要素O(n) |
挿入/削除の効率 | 任意の位置での要素の挿入と削除は非効率的です(データの移動) | 任意の位置に高効率で挿入および削除 |
イテレータ | オリジナルのエコロジカルポインター | 元の生態学的ポインターのカプセル化 |
イテレータの障害 | 挿入/削除/展開 | 削除 |
アプリケーションシナリオ | アクセス要素は多くなりますが、挿入と削除は少なくなります | 任意の位置でさらに挿入および削除 |