リスト中のC ++

リスト中のC ++

A、リストの紹介

  1. リストには、配列が挿入され、内側の範囲の任意の位置で容器の定数で除去し、容器は、双方向反復フロントことができることができるされています。
  2. 底部層は、二重リスト構造に連結され、無関係の別のノードに格納されている二重リンクリストの各要素を指し示すポインタがノード
    前部要素及び後部要素。
  3. 非常によく似たリストとforward_list:主な違いは、forward_listで、単一リンクリスト、前方にのみ反復で簡単に高許された
    効率を。
  4. 他の配列の容器(配列、ベクター、両端キュー)と比較して、リストが一般的に挿入される任意の位置で行われ、要素の除去効率が
    より良いです。
  5. リストにアクセスするには他の配列の容器と比較して、最大の欠陥リストとforward_listのような任意の位置へのランダムアクセス、サポートしていない
    と知られている位置から(例えば、頭部または尾部として)反復する必要があり、6つの要素のを位置は、この位置で反復線形時間を要する
    オーバーヘッド、リストはまだ大規模なストレージタイプリストの(各ノードの関連する情報を保存するためにいくつかの余分なスペースを必要としているこの小さな要素が
    重要な因子であってもよいです)

第二に、基本的な概略的なリストの構造
ここに画像を挿入説明
ノートを開始、終了、rbegin、レンド位置
リバースモードイテレータを印刷するノート

三、リストイテレータの失敗は、
私が前に言ったように、ここでは誰もが、イテレータのポインタに似ている、すなわち、障害**イテレータノードイテレータは、ノードが削除されていることを、無効を指していると理解することができます。根本的な構造は非常にリストに双方向循環リンクリスト一覧鉛ノードであるため、挿入されているが、故障リストイテレータ原因ではない、唯一の削除が失敗することはありません、故障のみ**と削除されたノードへのポイントイテレータ、他のイテレータは影響を受けません

void TestListIterator1()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋
值
l.erase(it);
++it;
}
}

//改正
void TestListIterator1()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋
值
it = l.erase(it);
}
}

四、リストのアナログ実装

namespace wolf
{
// List的节点类
template<class T>
struct ListNode
{
ListNode(const T& val = T())
: _pPre(nullptr)
, _pNext(nullptr)
, _val(val)
{}
ListNode<T>* _pPre;
ListNode<T>* _pNext;
T _val;
};
/*
List 的迭代器
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
1. 原生态指针,比如:vector
2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1. 指针可以解引用,迭代器的类中必须重载operator*()
2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前
移动,所以需要重载,如果是forward_list就不需要重载--
4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
*/
template<class T, class Ref, class Ptr>
class ListIterator
{
	typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr)
: _pNode(pNode)
{}
ListIterator(const Self& l)
: _pNode(l._pNode)
{}
T& operator*(){return _pNode->_val;}
T* operator->(){return &(operator*());}
Self& operator++()
{
_pNode = _pNode->_pNext;
return *this;
}
Self operator++(int)
{
Self temp(*this);
_pNode = _pNode->_pNext;
return temp;
}
Self& operator--();
Self& operator--(int);
bool operator!=(const Self& l){return _pNode != l._pNode;}
bool operator==(const Self& l){return _pNode != l._pNode;}
PNode _pNode;
};
template<class T>
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T&> const_iterator;
public:
///////////////////////////////////////////////////////////////
// List的构造
list()
{
CreateHead();
}
list(int n, const T& value = T())
{
CreateHead();
for (int i = 0; i < n; ++i)
push_back(value);
}
template <class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
list(const list<T>& l)
{
CreateHead();
// 用l中的元素构造临时的temp,然后与当前对象交换
list<T> temp(l.cbegin(), l.cend());
this->swap(temp);
}
list<T>& operator=(const list<T> l)
{
this->swap(l);
return *this;
}
~list()
{
clear();
delete _pHead;
_pHead = nullptr;
}
///////////////////////////////////////////////////////////////
// List Iterator
iterator begin(){return iterator(_pHead->_pNext);}
iterator end(){return iterator(_pHead);}
const_iterator begin(){return const_iterator(_pHead->_pNext);}
const_iterator end(){return const_iterator(_pHead);}
///////////////////////////////////////////////////////////////
// List Capacity
size_t size()const;
bool empty()const;
////////////////////////////////////////////////////////////
// List Access
T& front();
const T& front()const;
T& back();
const T& back()const;
////////////////////////////////////////////////////////////
// List Modify
void push_back(const T& val){insert(begin(), val);}
void pop_back(){erase(--end());}
void push_front(const T& val){insert(begin(), val);}
void pop_front(){erase(begin());}
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{
PNode pNewNode = new Node(val);
PNode pCur = pos._pNode;
// 先将新节点插入
pNewNode->_pPre = pCur->_pPre;
pNewNode->_pNext = pCur;
pNewNode->_pPre->_pNext = pNewNode;
pCur->_pPre = pNewNode;
return iterator(pNewNode);
}
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{
// 找到待删除的节点
PNode pDel = pos._pNode;
PNode pRet = pDel->_pNext;
// 将该节点从链表中拆下来并删除
pDel->_pPre->_pNext = pDel->_pNext;
pDel->_pNext->_pPre = pDel->_pPre;
delete pDel;
return iterator(pRet);
}
void clear();
void swap(List<T>& l);
private:
void CreateHead()
{
_pHead = new Node;
_pHead->_pPre = _pHead;
_pHead->_pNext = _pHead;
}
private:
PNode _pHead;
};
}

五、ベクトル、リストの比較

ベクター リスト
基本構造 連続空間の動的順序テーブル、 最初のノードの双方向循環リスト
ランダムアクセス ランダムアクセス、アクセス要素効率O(1)をサポート ランダムアクセス、アクセス要素効率O(N)をサポートしていません
挿入、削除 低い挿入及び欠失どこでも効率要素を移動させる必要があり、時間複雑度はO(N)であり、相溶化剤を挿入するとき、相溶化剤が必要になることができる:新しい寸法、コピー要素は、より低い効率をもたらす、古い空間を解放します 高効率のどこにでも挿入及び欠失、無移動エレメント、時間複雑度は、O(1)であります
宇宙利用 下層はない可能性が高い原因メモリの断片化、高スペース効率に、連続した空間で、 開くために高ダイナミックキャッシュの利用率下ノード、原因メモリの断片化の可能性が小さなノード、スペースの使用率が低い場合、キャッシュの低利用率
イテレータ オリジナルエコポインタ カプセル化されたプリミティブポインタ(ノードポインタ)
イテレータの失敗 要素を挿入するときに再膨張につながる可能性の要素インサートとして、元のイテレータの障害の原因となる、すべての反復子を再割り当てを与えるために、それは失敗し、現在の反復がそうでなければ必要と再割り当て、削除 あなたは要素を削除すると、インサート要素は、現在の反復が失敗につながるだけ、イテレータの失敗にはなりません、他のイテレータは影響を受けません
利用シナリオ 効率的なストレージの必要性、ランダムアクセスをサポートするには、効率性、削除、挿入を気にしません。 関係ないと挿入と削除操作の数が多いです、

マシンアクセス

公開された66元の記事 ウォン称賛28 ビュー60000 +

おすすめ

転載: blog.csdn.net/wolfGuiDao/article/details/104250685