C++模擬實(shí)現(xiàn)list功能
努力的最大好處,就在于你可以選擇你想要的生活,而不是被迫隨遇而安。

list介紹
1、 list是可以在**常數(shù)范圍O(1)**內(nèi)在任意位置進(jìn)行插入和刪除的序列式容器,并且該容器可以前后雙向迭代,但list容器不適合用來做排序。
2、list的底層是一個(gè)循環(huán)雙向鏈表結(jié)構(gòu),雙向鏈表中每個(gè)元素存儲(chǔ)在互不相關(guān)的獨(dú)立節(jié)點(diǎn)中,在節(jié)點(diǎn)中通過指針指向其前一個(gè)元素和后一個(gè)元素。
構(gòu)造函數(shù)
在C++98中l(wèi)ist的構(gòu)造函數(shù)加上拷貝構(gòu)造函數(shù)為如下四個(gè)。下面我們就模擬實(shí)現(xiàn)這里的全部的構(gòu)造函數(shù)。當(dāng)然我們這里并沒有像標(biāo)準(zhǔn)庫一樣使用空間配置器來創(chuàng)建空間,使用的是new運(yùn)算符,但原理都是創(chuàng)建一塊新的空間。

無參構(gòu)造函數(shù)
這里我們模擬默認(rèn)的構(gòu)造函數(shù),默認(rèn)值為T(),其含義為:該類型的默認(rèn)值int類型就為0,char類型為'\0',自定義類型會(huì)調(diào)用其構(gòu)造函數(shù)來初始化這個(gè)匿名對(duì)象得到默認(rèn)值。
list() //無參默認(rèn)構(gòu)造函數(shù)
{
this->m_head = new node(T());
this->m_head->m_next = this->m_head; //創(chuàng)建頭結(jié)點(diǎn),并讓頭結(jié)點(diǎn)的頭尾相連形成循環(huán)結(jié)構(gòu)
this->m_head->m_prev = this->m_head;
}
有參構(gòu)造函數(shù)
list(size_t size, const T& val=T()) //n個(gè)元素構(gòu)造函數(shù)
{
this->m_head = new node(T()); //創(chuàng)建頭結(jié)點(diǎn),并讓頭結(jié)點(diǎn)的頭尾相連形成循環(huán)結(jié)構(gòu)
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (size--)
{
this->push_back(val);
}
}
注意:
1、該構(gòu)造函數(shù)知道其需要用于存儲(chǔ)n個(gè)數(shù)據(jù)的空間,所以我們使用new運(yùn)算符開辟好空間,后用push_back()函數(shù)來尾插入val值。
2、該構(gòu)造函數(shù)還需要實(shí)現(xiàn)兩個(gè)重載函數(shù),如果不實(shí)現(xiàn)其重載函數(shù),會(huì)導(dǎo)致本來想調(diào)用n個(gè)元素構(gòu)造函數(shù)時(shí),編譯器會(huì)調(diào)用到我們下面要模擬實(shí)現(xiàn)的模板區(qū)間構(gòu)造函數(shù)。
list(long size, const T& val = T()) //n個(gè)元素構(gòu)造函數(shù)
{
assert(size > 0);
this->m_head = new node(T()); //創(chuàng)建頭結(jié)點(diǎn),并讓頭結(jié)點(diǎn)的頭尾相連形成循環(huán)結(jié)構(gòu)
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (size--)
{
this->push_back(val);
}
}
list(int size, const T& val = T()) //n個(gè)元素構(gòu)造函數(shù)
{
assert(size > 0);
this->m_head = new node(T()); //創(chuàng)建頭結(jié)點(diǎn),并讓頭結(jié)點(diǎn)的頭尾相連形成循環(huán)結(jié)構(gòu)
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (size--)
{
this->push_back(val);
}
}
可以看到,這兩個(gè)重載函數(shù)與之不同的就是其參數(shù)size的類型不同,但這卻是必要的,否則當(dāng)我們使用以下代碼時(shí),編譯器會(huì)優(yōu)先與模板區(qū)間構(gòu)造函數(shù)相匹配。
ZJ::list<int>L(2,1); //不實(shí)現(xiàn)重載版本會(huì)調(diào)用到模板區(qū)間構(gòu)造函數(shù)
并且因?yàn)闃?gòu)造函數(shù)2當(dāng)中對(duì)參數(shù)first和last進(jìn)行了解引用(*)(而int類型不能進(jìn)行解引用操作)而報(bào)錯(cuò)。
模板區(qū)間構(gòu)造函數(shù)
最后就是我們上面一直說到的模板區(qū)間構(gòu)造函數(shù)了,因?yàn)樵摰鲄^(qū)間可以是其他容器的迭代器區(qū)間,該函數(shù)接收到的迭代器的類型是不確定的,所以我們這里需要將該構(gòu)造函數(shù)設(shè)計(jì)為一個(gè)函數(shù)模板,在函數(shù)體內(nèi)將該迭代器區(qū)間的數(shù)據(jù)一個(gè)個(gè)尾插到容器當(dāng)中即可。
template <class InputIterator>
list(InputIterator first, InputIterator last) //區(qū)間構(gòu)造
{
this->m_head = new node(T()); //創(chuàng)建頭結(jié)點(diǎn)
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (first != last)
{
node* newnode = new node(*first);
node* tail = this->m_head->m_prev;
tail->m_next = newnode;
newnode->m_prev = tail;
newnode->m_next = this->m_head;
this->m_head->m_prev = newnode;
++first;
}
}
注意:
1、該區(qū)間必須是前閉后開[obj.begin(),obj.end());
拷貝構(gòu)造函數(shù)
拷貝構(gòu)造的思想是我們是很容易想到的,就是遍歷一遍我們要拷貝的對(duì)象obj鏈表,并將obj每個(gè)元素的值給this對(duì)象的每一個(gè)對(duì)應(yīng)的結(jié)點(diǎn),并將其每個(gè)結(jié)點(diǎn)都鏈接起來。
list(const list<T>& obj) //拷貝構(gòu)造函數(shù)
{
this->m_head = new node(T()); //創(chuàng)建頭結(jié)點(diǎn),并讓頭結(jié)點(diǎn)的頭尾相連形成循環(huán)結(jié)構(gòu)
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
const_iterator it = obj.begin();
while (it != obj.end())
{
node* newnode = new node(it.m_pnode->m_val); //創(chuàng)建新結(jié)點(diǎn)并把值賦予給它
node* tail = this->m_head->m_prev;
tail->m_next = newnode;
newnode->m_prev = tail;
newnode->m_next = this->m_head;
this->m_head->m_prev = newnode;
++it;
}
}
賦值運(yùn)算符重載
根據(jù)我們之前的博客的往歷,這里我們采用現(xiàn)代寫法,及用obj調(diào)用拷貝構(gòu)造函數(shù)創(chuàng)建一個(gè)臨時(shí)對(duì)象temp,并將temp與我們的this指針指向的對(duì)象的指針交換即可。
list<T>& operator=(const list<T>& obj) //賦值運(yùn)算符重載
{
if (this != &obj) //防止自我賦值
{
list<T>temp(obj);
this->swap(temp);
}
return *this; //返回自己
}
注意:
1、上面的temp臨時(shí)對(duì)象出了if語句時(shí)就會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)進(jìn)行釋放內(nèi)存,故不會(huì)造成內(nèi)存的泄漏等問題。
析構(gòu)函數(shù)
析構(gòu)函數(shù)這里,我就有點(diǎn)偷懶啦,復(fù)用了我們下面要模擬實(shí)現(xiàn)的pop_front()函數(shù),大致思路就是從頭到尾一個(gè)一個(gè)刪除結(jié)點(diǎn),并把頭結(jié)點(diǎn)也刪除并至空。
~list() //析構(gòu)函數(shù)
{
iterator it = this->begin();
while (it != this->end()) //復(fù)用我們寫的頭刪,一個(gè)一個(gè)的刪除,當(dāng)然也可以復(fù)用尾刪pop_back()和erase()
{
++it;
this->pop_front();
}
delete this->m_head;
this->m_head = nullptr;
}
迭代器
在C++中我們的迭代器有如下幾種:

下面我只模擬begin()和end()迭代器。
iterator begin()
{
return iterator(this->m_head->m_next);
}
const_iterator begin() const
{
return const_iterator(this->m_head->m_next);
}
iterator end()
{
return iterator(this->m_head);
}
const_iterator end() const
{
return const_iterator(this->m_head);
}
上面我們模擬實(shí)現(xiàn)了我們的迭代器,并且有普通迭代器和const迭代器。但是我們還要了解迭代器的原理是上面,在之前我們的博客中我們說過并不是每個(gè)迭代器都是原生指針,其中我們的list就是封裝了一個(gè)指針變量來達(dá)到實(shí)現(xiàn)iterator的結(jié)果。
typedef list_iterator<T,T&,T*> iterator; //普通迭代器 typedef list_iterator<T,const T&,const T*> const_iterator; //常量迭代器
可能有人會(huì)疑惑,上面這兩個(gè)迭代器不都差不多嘛,只是名字不一樣,為什么不直接在類型上加const,而是在模板參數(shù)上指定加上const屬性呢?我們要知道由于const對(duì)象只能調(diào)用常函數(shù),但是平時(shí)我們使用std::list時(shí)是不是可以支持 ++、-- 呢?如果是const對(duì)象,它只能調(diào)用常函數(shù),一旦加上變成const函數(shù),那我們的const迭代器就不能進(jìn)行++、–、' * '等,而我們要達(dá)到的效果是可以進(jìn)行++、–等,但僅僅是不能其元素的值而已。所以 我們這里封裝了一個(gè)模板指針。我們通過模板的參數(shù)不同來控制它的讀取操作。
迭代器構(gòu)造函數(shù)
就是將一個(gè)指針傳過來,并賦給我們的成員變量m_pnode。
list_iterator(node* pnode)
:m_pnode(pnode)
{}
迭代器關(guān)系運(yùn)算符重載
因?yàn)槲覀円獙?shí)現(xiàn)迭代器的相關(guān)遍歷操作例如下面的代碼:
ZJ::list<int>::iterator it = L1.begin(); it != L1.end()
bool operator!=(const myself&obj) const //重載!=號(hào)
{
return this->m_pnode != obj.m_pnode;
}
bool operator==(const myself& obj) const //重載==號(hào)
{
return this->m_pnode == obj.m_pnode;
}
迭代器++ --運(yùn)算符重載
其中下面返回的myself類型其實(shí)就是我們的迭代器這個(gè)類的類型,只是我們將其typedef了一下代碼如下:
typedef list_iterator<T, Ref, Ptr>myself;
這里重載的前置與后置要分別開來,后置需要使用int占位符來占位,不然會(huì)發(fā)生錯(cuò)誤。
myself& operator++() //重載前置++
{
//由于我們的list是雙向循環(huán)鏈表,我們的++,就是指向下一個(gè)結(jié)點(diǎn)
this->m_pnode = this->m_pnode->m_next;
return *this;
}
myself operator++(int) //重載后置++
{
const myself temp(*this);
this->m_pnode = this->m_pnode->m_next;
return temp;
}
myself& operator--() //重載前置--
{
//由于我們的list是雙向循環(huán)鏈表,我們的--就是得到它上一個(gè)結(jié)點(diǎn)的迭代器
this->m_pnode = this->m_pnode->m_prev;
return *this;
}
myself operator--(int) //重載后置--
{
const myself temp(*this);
this->m_pnode = this->m_pnode->m_prev;
return temp;
}
迭代器 * 運(yùn)算符重載
由于我們知道Ref是由兩種類型的,一種是T&,另一種是const T&,所以當(dāng)我們的對(duì)象是const對(duì)象時(shí),我們可以控制它不讓其修改。
Ref operator* () //重載 *
{
return this->m_pnode->m_val;
}
迭代器 -> 運(yùn)算符重載
為什么要重載->運(yùn)算符呢?這是因?yàn)槿绻覀僱ist中存儲(chǔ)的是自定義類型時(shí),我們的迭代器無法使用->去得到其成員。
Ptr operator->() //重載 ->
{
return &this->m_pnode->m_val;
}
總結(jié)
到了這里可能會(huì)有人會(huì)問為什么我們不寫迭代器的拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)呢?
答:這是因?yàn)槲覀兊牡魇怯脕肀闅v容器中的部分或全部元素,每個(gè)迭代器對(duì)象代表容器中的確定的地址,并且這些結(jié)點(diǎn)元素析構(gòu)和拷貝并不歸我們管,結(jié)點(diǎn)應(yīng)該歸我們的list管,所以編譯器默認(rèn)提供的淺拷貝就已經(jīng)足夠了。
容量相關(guān)函數(shù)
empty()
功能:是用來獲取容器中是否為空。
返回值:bool。
bool empty() const //判空
{
return this->begin() == this->end(); //就是begin()與end()同時(shí)指向頭結(jié)點(diǎn)時(shí)的情況
}
size()
功能:是用來獲取元素的個(gè)數(shù)。
返回值:size_t(無符號(hào)整型)。
注意:但是在鏈表中這個(gè)接口并不常用。如果頻繁的調(diào)用該接口會(huì)造成性能的下降。
//遍歷一遍鏈表來得到元素個(gè)數(shù),為什么使用遍歷一遍鏈表呢?
//這是因?yàn)槲覀兪褂面湵頃r(shí)很少會(huì)去知道它的元素個(gè)數(shù),但如果頻繁的調(diào)用該接口會(huì)造成性能的下降
//此時(shí)我們應(yīng)該在list類中將增加一個(gè)記錄元素個(gè)數(shù)的變量size
//如果有元素插入就增加,刪除就減少
size_t size() const //獲得元素個(gè)數(shù)
{
size_t size = 0;
const_iterator it = this->begin();
while(it!=this->end())
{
++it;
++size;
}
return size;
}
元素訪問相關(guān)函數(shù)
back()
- 功能:獲取最后一個(gè)元素的值。
- 返回值:存儲(chǔ)的類型的引用。
T& back()
{
assert(!this->empty());
return this->m_head->m_prev->m_val;
}
const T& back() const
{
assert(!this->empty());
return this->m_head->prev->m_val;
}
front()
- 功能:獲取第一個(gè)元素的值。
- 返回值:存儲(chǔ)的類型的引用。
T& front()
{
assert(!this->empty());
return this->m_head->m_next->m_val;
}
const T& front() const
{
assert(!this->empty());
return this->m_head->m_next->m_val;
}
修改相關(guān)函數(shù)
push_back()
- 功能:在尾部插入一個(gè)元素。
- 返回值:void(無返回值)。
void push_back(const T& val) //尾插
{
node* tail = this->m_head->m_prev; //指向尾部結(jié)點(diǎn)
node* newnode = new node(val); //創(chuàng)建新結(jié)點(diǎn)
newnode->m_next = tail->m_next; //將新結(jié)點(diǎn)的m_next指向頭結(jié)點(diǎn)
newnode->m_prev = tail; //將新結(jié)點(diǎn)m_prev指向tail結(jié)點(diǎn)
tail->m_next = newnode; //并將原來的尾結(jié)點(diǎn)的m_next指向newnode
this->m_head->m_prev = newnode; //并將頭結(jié)點(diǎn)的m_prev指向新的尾
}
push_front()
- 功能:在頭部插入一個(gè)元素。
- 返回值:void(無返回值)。
void push_front(const T& val) //頭插
{
node* newnode = new node(val); //創(chuàng)建新結(jié)點(diǎn)
node* next = this->m_head->m_next; //指向第一個(gè)結(jié)點(diǎn)
newnode->m_next = next; //將創(chuàng)建的新結(jié)點(diǎn)newnode的m_next指向我們?cè)瓉淼牡谝粋€(gè)元素next
this->m_head->m_next = newnode; //在將我們的頭結(jié)點(diǎn)的m_next指向新創(chuàng)建的結(jié)點(diǎn)
newnode->m_prev = this->m_head; //在將新結(jié)點(diǎn)的m_prev指向頭結(jié)點(diǎn)
next->m_prev = newnode; //在將原先第一個(gè)結(jié)點(diǎn)元素的m_prev指向新創(chuàng)建的結(jié)點(diǎn)
}
pop_back()
- 功能:在尾部刪除一個(gè)元素。
- 返回值:void(無返回值)。
void pop_back() //尾刪
{
assert(!empty()); //斷言 如果list已經(jīng)為空,則刪除不了
node* tail = this->m_head->m_prev; //先找到我們要?jiǎng)h除的尾結(jié)點(diǎn)
node* prev = tail->m_prev; //再找到要?jiǎng)h除的尾結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
this->m_head->m_prev = prev; //將頭結(jié)點(diǎn)的m_prev指向新的尾prev
prev->m_next = this->m_head; //再將prev的m_next指向頭結(jié)點(diǎn)
tail->m_next = tail->m_prev = nullptr; //把要?jiǎng)h除的元素的成員至nullptr
tail->m_val = T(); //將要?jiǎng)h除的元素的值置為匿名對(duì)象的默認(rèn)值
delete tail; //刪除尾結(jié)點(diǎn)
}
pop_front()
- 功能:在頭部刪除一個(gè)元素。
- 返回值:void(無返回值)。
void pop_front() //頭刪
{
assert(!empty()); //斷言 如果list已經(jīng)為空,則刪除不了
node* delnode = this->m_head->m_next; //先找到我們要?jiǎng)h除的第一個(gè)結(jié)點(diǎn)位置
node* next = delnode->m_next; //在找到刪除結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)的位置
this->m_head->m_next = next; //再將頭結(jié)點(diǎn)的m_next指向我們新的第一個(gè)結(jié)點(diǎn)
next->m_prev = this->m_head; //再將我們的新的第一個(gè)結(jié)點(diǎn)的m_prev指向頭結(jié)點(diǎn)
delnode->m_next = delnode->m_prev = nullptr; //把要?jiǎng)h除的元素的成員至nullptr
delnode->m_val = T(); //將要?jiǎng)h除的元素的值置為匿名對(duì)象的默認(rèn)值
delete delnode; //刪除第一個(gè)結(jié)點(diǎn)
}
insert()
在c++98中我們的insert()函數(shù)有如下三種版本:

下面我們就將其模擬實(shí)現(xiàn):
指定位置插入一個(gè)元素
- 功能:在指定位置插入一個(gè)元素。
- 返回值:插入的元素的位置的迭代器。
//插入元素到指定位置,返回的是插入的元素的迭代器
iterator insert(iterator pos, const T& val)
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
node* newnode = new node(val); //創(chuàng)建新結(jié)點(diǎn)
node* cur = pos.m_pnode; //記錄當(dāng)前結(jié)點(diǎn)的指針
node* prev = cur->m_prev; //記錄當(dāng)前結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)的指針
newnode->m_next = cur;
newnode->m_prev = prev;
prev->m_next = newnode;
cur->m_prev = newnode;
return iterator(newnode); //返回一個(gè)用當(dāng)前的插入的元素的結(jié)點(diǎn)構(gòu)建的匿名對(duì)象的迭代器
}
指定位置插入n個(gè)相同的元素
- 功能:在指定位置插入一個(gè)元素。
- 返回值:void(無返回值)。
void insert(iterator pos, size_t n, const T& val) //插入n個(gè)val
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
while (n--)
{
node* newnode = new node(val);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
}
}
void insert(iterator pos, int n, const T& val) //插入n個(gè)val
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
assert(n > 0);
while (n--)
{
node* newnode = new node(val);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
}
}
void insert(iterator pos, long n, const T& val) //插入n個(gè)val
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
assert(n > 0);
while (n--)
{
node* newnode = new node(val);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
}
}
注意:這里的insert在指定位置插入為什么要實(shí)現(xiàn)三種重載版本呢?這與上面的構(gòu)造函數(shù)問題是相同類型的,都是與模板區(qū)間構(gòu)造有關(guān),這里就不多贅述了。
指定位置插入?yún)^(qū)間內(nèi)的元素
- 功能:在指定位置插入?yún)^(qū)間內(nèi)的元素。
- 返回值:void(無返回值)。
- 注意:
1、該區(qū)間必須是前閉后開;
template <class InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last) //區(qū)間插入
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
while (first != last)
{
node* newnode = new node(*first);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
++first;
}
}
erase()
在C++98中erase()有兩種版本,一個(gè)是刪除指定位置,另一個(gè)是刪除區(qū)間內(nèi)的元素。如下圖所示:

刪除指定位置
- 功能:刪除指定位置的元素。
- 返回值:刪除指定位置的元素的下一個(gè)結(jié)點(diǎn)的迭代器。
//刪除指定位置的元素,返回下一個(gè)元素的迭代器,但要注意的是:
//如果刪除的最后一個(gè)元素,此時(shí)返回的是頭結(jié)點(diǎn)也就是end()位置的迭代器
iterator erase(iterator pos)
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
assert(pos != end()); //斷言 list內(nèi)元素為空及刪除頭結(jié)點(diǎn)的情況
node* next = pos.m_pnode->m_next;
node* prev = pos.m_pnode->m_prev;
prev->m_next = next;
next->m_prev = prev;
pos.m_pnode->m_next = pos.m_pnode->m_prev = nullptr;
pos.m_pnode->m_val = T();
delete pos.m_pnode;
return iterator(next);
}
刪除區(qū)間內(nèi)的元素
- 功能:刪除區(qū)間內(nèi)的元素。
- 返回值:刪除區(qū)間內(nèi)的元素的下一個(gè)結(jié)點(diǎn)的迭代器。也就是返回last迭代器這個(gè)位置。
- 注意:
1、該區(qū)間必須是前閉后開;
iterator erase(iterator first, iterator last) //區(qū)間刪除
{
node* prev = first.m_pnode->m_prev;
node* next = last.m_pnode;
while (first != last)
{
node* cur = first.m_pnode;
++first;
cur->m_next = cur->m_prev = nullptr;
cur->m_val = T();
delete cur;
cur = nullptr;
}
prev->m_next = next;
next->m_prev = prev;
return iterator(next);
}
clear()
- 功能:用于清空我們list中的所有元素的值,但不是要把list對(duì)象也刪除。
- 返回值:void(無返回值)。
void clear() //清空元素,而不是把整個(gè)鏈表刪除掉
{
iterator it = this->begin();
while (it != this->end())
//復(fù)用我們寫的頭刪,一個(gè)一個(gè)的刪除,當(dāng)然也可以復(fù)用尾刪pop_back()和erase()
{
++it;
this->pop_front();
}
}
swap()
- 功能:swap顧名思義就是交換的意思,這里我們將這個(gè)swap作為我們的成員函數(shù),用來交換兩個(gè)list鏈表。
- 返回值: void(無返回值)。
void swap(list<T>& obj)
{
node* temp = this->m_head;
this->m_head = obj.m_head;
obj.m_head = temp;
}
完整代碼如下
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
using namespace std;
namespace ZJ
{
template<class T>
class list_node //結(jié)點(diǎn)
{
public:
list_node(T val=T()) //構(gòu)造函數(shù)
:m_val(val)
,m_prev(nullptr)
,m_next(nullptr)
{}
public:
T m_val; //值
list_node<T>* m_prev; //指向前一個(gè)的指針
list_node<T>* m_next; //指向下一個(gè)的指針
};
template<class T,class Ref,class Ptr> //封裝一個(gè)node型指針,制作成迭代器類
class list_iterator
{
public:
typedef list_node<T> node;
typedef list_iterator<T, Ref, Ptr>myself;
list_iterator(node* pnode)
:m_pnode(pnode)
{}
Ref operator* () //重載 *
{
return this->m_pnode->m_val;
}
Ptr operator->() //重載 ->
{
return &this->m_pnode->m_val;
}
bool operator!=(const myself&obj) const //重載!=號(hào)
{
return this->m_pnode != obj.m_pnode;
}
bool operator==(const myself& obj) const //重載==號(hào)
{
return this->m_pnode == obj.m_pnode;
}
myself& operator++() //重載前置++
{
this->m_pnode = this->m_pnode->m_next;
return *this;
}
myself operator++(int) //重載后置++
{
const myself temp(*this);
this->m_pnode = this->m_pnode->m_next;
return temp;
}
myself& operator--() //重載前置--
{
this->m_pnode = this->m_pnode->m_prev;
return *this;
}
myself operator--(int) //重載后置--
{
const myself temp(*this);
this->m_pnode = this->m_pnode->m_prev;
return temp;
}
public:
node* m_pnode;
};
template<class T>
class list
{
public:
typedef list_node<T> node;
typedef list_iterator<T,T&,T*> iterator; //普通迭代器
typedef list_iterator<T,const T&,const T*> const_iterator; //常量迭代器
public:
list() //無參默認(rèn)構(gòu)造函數(shù)
{
this->m_head = new node(T());
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
}
list(size_t size, const T& val=T()) //n個(gè)元素構(gòu)造函數(shù)
{
this->m_head = new node(T());
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (size--)
{
this->push_back(val);
}
}
list(long size, const T& val = T()) //n個(gè)元素構(gòu)造函數(shù)
{
assert(size > 0);
this->m_head = new node(T());
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (size--)
{
this->push_back(val);
}
}
list(int size, const T& val = T()) //n個(gè)元素構(gòu)造函數(shù)
{
assert(size > 0);
this->m_head = new node(T());
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (size--)
{
this->push_back(val);
}
}
template <class InputIterator>
list(InputIterator first, InputIterator last) //區(qū)間構(gòu)造
{
this->m_head = new node(T());
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
while (first != last)
{
node* newnode = new node(*first);
node* tail = this->m_head->m_prev;
tail->m_next = newnode;
newnode->m_prev = tail;
newnode->m_next = this->m_head;
this->m_head->m_prev = newnode;
++first;
}
}
list(const list<T>& obj) //拷貝構(gòu)造函數(shù)
{
this->m_head = new node(T());
this->m_head->m_next = this->m_head;
this->m_head->m_prev = this->m_head;
const_iterator it = obj.begin();
while (it != obj.end())
{
node* newnode = new node(it.m_pnode->m_val);
node* tail = this->m_head->m_prev;
tail->m_next = newnode;
newnode->m_prev = tail;
newnode->m_next = this->m_head;
this->m_head->m_prev = newnode;
++it;
}
}
list<T>& operator=(const list<T>& obj) //賦值運(yùn)算符重載
{
if (this != &obj)
{
list<T>temp(obj);
this->swap(temp);
}
return *this;
}
~list() //析構(gòu)函數(shù)
{
iterator it = this->begin();
while (it != this->end()) //復(fù)用我們寫的頭刪,一個(gè)一個(gè)的刪除,當(dāng)然也可以復(fù)用尾刪pop_back()和erase()
{
++it;
this->pop_front();
}
delete this->m_head;
this->m_head = nullptr;
}
iterator begin()
{
return iterator(this->m_head->m_next);
}
const_iterator begin() const
{
return const_iterator(this->m_head->m_next);
}
iterator end()
{
return iterator(this->m_head);
}
const_iterator end() const
{
return const_iterator(this->m_head);
}
bool empty() const //判空
{
return this->begin() == this->end(); //就是begin()與end()同時(shí)指向頭結(jié)點(diǎn)時(shí)的情況
}
//遍歷一遍鏈表來得到元素個(gè)數(shù),為什么使用遍歷一遍鏈表呢?
//這是因?yàn)槲覀兪褂面湵頃r(shí)很少會(huì)去知道它的元素個(gè)數(shù),但如果頻繁的調(diào)用該接口會(huì)造成性能的下降
//此時(shí)我們應(yīng)該在list類中將增加一個(gè)記錄元素個(gè)數(shù)的變量size
//如果有元素插入就增加,刪除就減少
size_t size() const //獲得元素個(gè)數(shù)
{
size_t size = 0;
const_iterator it = this->begin();
while(it!=this->end())
{
++it;
++size;
}
return size;
}
T& back()
{
assert(!this->empty());
return this->m_head->m_prev->m_val;
}
const T& back() const
{
assert(!this->empty());
return this->m_head->prev->m_val;
}
T& front()
{
assert(!this->empty());
return this->m_head->m_next->m_val;
}
const T& front() const
{
assert(!this->empty());
return this->m_head->m_next->m_val;
}
void push_front(const T& val) //頭插
{
node* newnode = new node(val);
node* next = this->m_head->m_next;
newnode->m_next = next;
this->m_head->m_next = newnode;
newnode->m_prev = this->m_head;
next->m_prev = newnode;
}
void push_back(const T& val) //尾插
{
node* tail = this->m_head->m_prev;
node* newnode = new node(val);
newnode->m_next = tail->m_next;
newnode->m_prev = tail;
tail->m_next = newnode;
this->m_head->m_prev = newnode;
}
//插入元素到指定位置,返回的是插入的元素的迭代器
iterator insert(iterator pos, const T& val)
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
node* newnode = new node(val); //創(chuàng)建新結(jié)點(diǎn)
node* cur = pos.m_pnode; //記錄當(dāng)前結(jié)點(diǎn)的指針
node* prev = cur->m_prev; //記錄當(dāng)前結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)的指針
newnode->m_next = cur;
newnode->m_prev = prev;
prev->m_next = newnode;
cur->m_prev = newnode;
return iterator(newnode); //返回一個(gè)用當(dāng)前的插入的元素的結(jié)點(diǎn)構(gòu)建的匿名對(duì)象的迭代器
}
void insert(iterator pos, size_t n, const T& val) //插入n個(gè)val
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
while (n--)
{
node* newnode = new node(val);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
}
}
void insert(iterator pos, int n, const T& val) //插入n個(gè)val
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
assert(n > 0);
while (n--)
{
node* newnode = new node(val);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
}
}
void insert(iterator pos, long n, const T& val) //插入n個(gè)val
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
assert(n > 0);
while (n--)
{
node* newnode = new node(val);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
}
}
template <class InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last) //區(qū)間插入
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
while (first != last)
{
node* newnode = new node(*first);
node* cur = pos.m_pnode;
node* prev = cur->m_prev;
newnode->m_prev = prev;
prev->m_next = newnode;
newnode->m_next = cur;
cur->m_prev = newnode;
++first;
}
}
void pop_front() //頭刪
{
assert(!empty()); //斷言 如果list已經(jīng)為空,則刪除不了
node* delnode = this->m_head->m_next;
node* next = delnode->m_next;
this->m_head->m_next = next;
next->m_prev = this->m_head;
delnode->m_next = delnode->m_prev = nullptr;
delnode->m_val = T();
delete delnode;
}
void pop_back() //尾刪
{
assert(!empty()); //斷言 如果list已經(jīng)為空,則刪除不了
node* tail = this->m_head->m_prev;
node* prev = tail->m_prev;
this->m_head->m_prev = prev;
prev->m_next = this->m_head;
tail->m_next = tail->m_prev = nullptr;
tail->m_val = T();
delete tail;
}
//刪除指定位置的元素,返回下一個(gè)元素的迭代器,但要注意的是:
//如果刪除的最后一個(gè)元素,此時(shí)返回的是頭結(jié)點(diǎn)也就是end()位置的迭代器
iterator erase(iterator pos)
{
assert(pos.m_pnode != nullptr); //斷言 迭代器是否為空指針錯(cuò)誤
assert(pos != end()); //斷言 list內(nèi)元素為空及刪除頭結(jié)點(diǎn)的情況
node* next = pos.m_pnode->m_next;
node* prev = pos.m_pnode->m_prev;
prev->m_next = next;
next->m_prev = prev;
pos.m_pnode->m_next = pos.m_pnode->m_prev = nullptr;
pos.m_pnode->m_val = T();
delete pos.m_pnode;
return iterator(next);
}
iterator erase(iterator first, iterator last) //區(qū)間刪除
{
node* prev = first.m_pnode->m_prev;
node* next = last.m_pnode;
while (first != last)
{
node* cur = first.m_pnode;
++first;
cur->m_next = cur->m_prev = nullptr;
cur->m_val = T();
delete cur;
cur = nullptr;
}
prev->m_next = next;
next->m_prev = prev;
return iterator(next);
}
void clear() //清空元素,而不是把整個(gè)鏈表刪除掉
{
iterator it = this->begin();
while (it != this->end()) //復(fù)用我們寫的頭刪,一個(gè)一個(gè)的刪除,當(dāng)然也可以復(fù)用尾刪pop_back()和erase()
{
++it;
this->pop_front();
}
}
void swap(list<T>& obj)
{
node* temp = this->m_head;
this->m_head = obj.m_head;
obj.m_head = temp;
}
private:
node* m_head; //頭指針
};
}
到此這篇關(guān)于C++模擬實(shí)現(xiàn)list的文章就介紹到這了,更多相關(guān)C++list實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)之迷宮求解問題
這篇文章主要為大家詳細(xì)介紹了C語言數(shù)據(jù)結(jié)構(gòu)之迷宮求解問題,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
在C++?Qt中實(shí)現(xiàn)異步散列器的代碼示例
在很多工作中,我們需要計(jì)算數(shù)據(jù)或者文件的散列值,例如登錄或下載文件,而在?Qt?中,負(fù)責(zé)這項(xiàng)工作的類為?QCryptographicHash,本文給大家介紹了在C++?Qt中實(shí)現(xiàn)異步散列器的代碼示例,需要的朋友可以參考下2024-09-09
C++實(shí)現(xiàn)對(duì)回收站里的文件進(jìn)行操作的示例代碼
這篇文章主要為大家詳細(xì)介紹了C++如何使用代碼對(duì)回收站里的文件進(jìn)行操作,譬如文件的刪除與恢復(fù)等,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
用C語言求解一元二次方程的簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了用C語言求解一元二次方程的簡(jiǎn)單實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
解決pip?install?dlib報(bào)錯(cuò)C++11?is?required?to?use?dlib
這篇文章主要介紹了在使用pip?install?dlib安裝dlib的時(shí)候報(bào)錯(cuò)C++11?is?required?to?use?dlib的解決方法,需要的的小伙伴可以參考一下,希望對(duì)你有所幫助2022-02-02

