首先要知道list就是一個帶頭循環(huán)雙向鏈表,在博主以前的文章有過詳細講解順序表和鏈表超詳細大總結
現在我們首先就要實現每個節(jié)點的類:
templatestruct ListNode
{ListNode(const T& val = T())
: _prev(nullptr)
, _next(nullptr)
, _val(val)
{}
ListNode* _prev;
ListNode* _next;
T _val;
};
1.2 list類的成員變量list的成員變量只需要頭節(jié)點
typedef ListNodeNode;
private:
Node* _head;
二、迭代器實現????
2.1 正向迭代器按照以前的思路寫迭代器如下:
templatestruct _list_iterator
{typedef ListNodeNode;
_list_iterator(Node* p)
{ _p = p;
}
T& operator*()
{ return _p->_val;
}
_list_iterator& operator++()
{ _p = _p->_next;
return *this;
}
_list_iterator& operator++(int)
{ _list_iteratortmp(*this);
_p = _p->_next;
return tmp;
}
_list_iterator& operator--()
{ _p = _p->_prev;
return *this;
}
_list_iterator& operator--(int)
{ _list_iteratortmp(*this);
_p = _p->_prev;
return tmp;
}
//end() 返回臨時變量具有常屬性
bool operator!=(const _list_iterator& it) const
{ return _p != it._p;
}
bool operator!=(const _list_iterator& it) const
{ return _p == it._p;
}
Node* _p;
};
我們還有個迭代器叫做const迭代器,就是可以++
,--
,*
,就是用的時候不能修改。也就是不能返回T&
而是const T&
有人可能想實現一個const版本的重載:
const T& operator*() const
{ return _p->_val;
}
但現在我們的容器是const,傳的迭代器沒有變,想要修改還是可以。
為了解決這個問題,第一個方法是拷貝一份迭代器,換個名字,在使用上面的const版本*
重載即可。但這樣就會造成代碼冗余。
所以我們可以這樣修改:
typedef _list_iteratoriterator;
typedef _list_iteratorconst_iterator;
傳入兩個模板參數,迭代器模板使用template
再把*
重載改成:
Ref operator*()
{ return _p->_val;
}
雙模板參數迭代器實現如下:
templatestruct _list_iterator
{typedef ListNodeNode;
typedef _list_iteratoriterator;
_list_iterator(Node* p)
{ _p = p;
}
Ref operator*()
{ return _p->_val;
}
iterator& operator++()
{ _p = _p->_next;
return *this;
}
iterator& operator++(int)
{ _list_iteratortmp(*this);
_p = _p->_next;
return tmp;
}
iterator& operator--()
{ _p = _p->_prev;
return *this;
}
iterator& operator--(int)
{ iterator tmp(*this);
_p = _p->_prev;
return tmp;
}
//end() 返回臨時變量具有常屬性
bool operator!=(const iterator& it) const
{ return _p != it._p;
}
bool operator==(const iterator& it) const
{ return _p == it._p;
}
Node* _p;
};
但是我們可以發(fā)現還有一個問題:*
重載如果是原生類型好說,但是對于自定義類型我們需要取出每一個對象就需要重載->
。
例如我們想要打印日期類的年月日,直接*
取出的是節(jié)點。所以我們可以重載一個->
拿到節(jié)點。
T* operator->()
{return &_p->_val;
}
打印年月日就可以這么寫:
list::iterator it = lt.begin();
while (it != lt.end())
{cout<< it->year<< it->month<< it->day<< endl;
++it;
}
其實這里應該寫成it->->year
,為了可讀性編譯器優(yōu)化省略了一個->
。而且所有類型只要想重載->都會這樣省略。而重載->
又會涉及到是否能修改的問題。所以再傳一個模板參數。
typedef _list_iteratoriterator;
typedef _list_iteratorconst_iterator;
對于迭代器:
Ptr operator->()
{ return &_p->_val;
}
2.2 反向迭代器其實正向迭代器就是對Node* 指針的封裝,而反向迭代器就是正向迭代器的封裝。
反向迭代器的--
就是正向迭代器的++
。
而比較大的區(qū)別時反向迭代器的*
重載取得不是當前位置,而是前一個位置的值。
正向迭代器的開始就是反向迭代器的結束,正向迭代器的結束就是反向迭代器的開始。
代碼如下:
namespace yyh
{templatestruct reverse_iterator
{typedef reverse_iteratoriterator;
// 封裝正向迭代器
reverse_iterator(Iterator it)
: _it(it)
{}
Ref operator*()
{ Iterator tmp = _it;
return *--tmp;
}
Ptr operator->()
{ Iterator tmp = _it;
return &--tmp;
}
iterator& operator++()
{ --_it;
return *this;
}
iterator& operator++(int)
{ iterator tmp(*this);
--_it;
return tmp;
}
iterator& operator--()
{ ++_it;
return *this;
}
iterator& operator--(int)
{ iterator tmp(*this);
++_it;
return tmp;
}
bool operator==(const iterator& it) const
{ return _it == it._it;
}
bool operator!=(const iterator& it) const
{ return _it != it._it;
}
Iterator _it;
};
}
三、list類接口的實現
3.1 構造函數_list_iterator(Node* p)
{ _p = p;
}
3.2 begin()和end()iterator begin()
{ return iterator(_head->_next);
}
iterator end()
{ return iterator(_head);
}
const const_iterator begin() const
{ return const_iterator(_head->_next);
}
const const_iterator end() const
{ return const_iterator(_head);
}
3.3 插入iterator insert(iterator pos, const T& val)
{ Node* cur = pos._p;
Node* prev = cur->_prev;
Node* newnode = new Node(val);
cur->_prev = newnode;
newnode->_next = cur;
prev->_next = newnode;
newnode->_prev = prev;
return iterator(newnode);
}
3.4 頭插和尾插void push_back(const T& val)
{ insert(end(), val);
}
void push_front(const T& val)
{ insert(begin(), val);
}
3.5 刪除iterator erase(iterator pos)
{ assert(pos != end());
Node* prev = pos._p->_prev;
Node* next = prev->_next->_next;
delete pos._p;
prev->_next = next;
next->_prev = prev;
return iterator(next);
}
3.6 頭刪和尾刪void pop_back()
{ erase(--end());
}
void pop_front()
{ erase(begin());
}
3.7 clear()和析構~list()
{ clear();
delete _head;
_head = nullptr;
}
void clear()
{ iterator it = begin();
while (it != end())
{ it = erase(it);
}
}
3.8 拷貝構造list(const list& lt)
{ // 先創(chuàng)建頭節(jié)點
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
const_iterator it = lt.begin();
while (it != lt.end())
{ push_back(*it);
++it;
}
}
這里要注意先創(chuàng)建頭節(jié)點,再插入數據。
3.8.1 現代寫法// 迭代器區(qū)間初始化
templatelist(InputIterator first, InputIterator last)
{ // 先創(chuàng)建頭節(jié)點
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
while (first != last)
{ push_back(*first);
++first;
}
}
list(const list& lt)
{ _head = new Node;// _head不能為nullptr,析構會解用
_head->_next = _head;
_head->_prev = _head;
listtmp(lt.begin(), lt.end());
swap(_head, tmp._head);
}
這里如果給_head賦值為nullptr,后邊調用clear()會用到return iterator(_head->_next);
,程序崩潰。
list& operator=(const list& lt)
{ if (this != <)
{ clear();
for (auto& e : lt)
{push_back(e);
}
}
return *this;
}
3.9.1 現代寫法list& operator=(listlt)
{ _head->_next = _head;
_head->_prev = _head;
swap(_head, lt._head);
return *this;
}
3.10 初始化沖突問題當我們想用n個val初始化的時候:
list(size_t n, const T& val = T())
{ _head = new Node;
_head->_next = _head;
_head->_prev = _head;
for (size_t i = 0; i< n; i++)
{ push_back(val);
}
}
但是我們前面使用迭代器初始化:
templatelist(InputIterator first, InputIterator last)
{ // 先創(chuàng)建頭節(jié)點
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
while (first != last)
{ push_back(*first);
++first;
}
}
當我們使用list
時,此時我們就會傳到迭代器區(qū)間初始化,造成尋址錯誤。
解決方法:
重載一個int 類型的初始化函數:
list(size_t n, const T& val = T())
{ _head = new Node;
_head->_next = _head;
_head->_prev = _head;
for (size_t i = 0; i< n; i++)
{ push_back(val);
}
}
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
分享名稱:【C++】list類模擬實現-創(chuàng)新互聯
本文來源:http://aaarwkj.com/article36/jcgpg.html
成都網站建設公司_創(chuàng)新互聯,為您提供網站收錄、網頁設計公司、微信小程序、做網站、移動網站建設、網站設計公司
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯