目錄
1,list的介紹及使用
2,list_node
3,list_node()
3,list
4,list()
5,push_back(const T& x)
6,print()
7,_list_iterator
8,operator*()
9,begin()
10,end()
11,operator->()
12,operator++()
13,operator++(int)
14,operator--()
15,operator--(int)
16,operator==(const sefl& s)
17,operator!=(const sefl& s)
18,_list_const_iterator
19,list(iterator first, iterator last)
20,begin()const
21,end()const
22,list(const list& lt)
23,operator=(list lt)
24,insert(iterator pos, const T& x)
25,erase(iterator pos)
26,clear()
27,~list()
28,push_front(const T& x)
29,pop_front()
30,pop_back()
31,源代碼
32,總結(jié)
1,list的介紹及使用
1,list 是可以在常數(shù)范圍內(nèi)在任意位置進行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。
2,list 的底層是雙向鏈表結(jié)構(gòu),雙向鏈表中每個元素存儲在互不相關(guān)的獨立節(jié)點中,在節(jié)點中通過指針指向其前一個元素和后一個元素。
3,list 與 forward_list 非常相似:最主要的不同在于 forward_list 是單鏈表,只能朝前迭代,已讓其更簡單高效。
4,與其他的序列式容器相比(array,vector,deque),list通常在任意位置進行插入、移除元素的執(zhí)行效率更好。
5,與其他序列式容器相比,list 和 forward_list 最大的缺陷是不支持任意位置的隨機訪問,比如:要訪問 list 的第6個元素,必須從已知的位置(比如頭部或者尾部)迭代到該位置,在這段位置上迭代需要線性的時間開銷;list 還需要一些額外的空間,以保存每個節(jié)點的相關(guān)聯(lián)信息(對于存儲類型較小元素的大list來說這可能是一個重要的因素)
2,list_node
結(jié)點的結(jié)構(gòu)體框架
template<class T>
struct list_node
{
list_node<T>* _next;
list_node<T>* _prev;
T data;
};
因為是雙向循環(huán)鏈表,需要一個上指針 _prev,下指針 _next,還有數(shù)據(jù) data;
3,list_node()
對結(jié)點進行初始化
list_node(const T& x = T())
:_next(nullptr)
, _prev(nullptr)
, data(x)
{}
然后還要將其初始化,指針為空,數(shù)據(jù)為內(nèi)置類型初始化的值;
3,list
鏈表結(jié)構(gòu)框架
template <class T>
class list
{
typedef list_node<T> node;
public:
private:
node* _head;
};
鏈表是帶頭結(jié)點的,所以我們需要一個哨兵位頭結(jié)點;
4,list()
對鏈表初始化
void empty_init()
{
_head = new node;
_head->_next = _head;
_head->_prev = _head;
}
list()
{
empty_init();
}
因為我們是雙向循環(huán)鏈表,所以我們的下一個結(jié)點和上一個結(jié)點都是指向自己的,形成一個環(huán);
5,push_back(const T& x)
尾插
void push_back(const T& x)
{
node* tail = _head->_prev;
node* newnode = new node(x);
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}
我們先找到尾結(jié)點(tail),申請一個新結(jié)點,然后就插入其中;
6,print()
打印數(shù)據(jù)
void print()
{
node* cur = _head->_next;
while (cur != _head)
{
cout << cur->data << " ";
cur = cur->_next;
}
}
哨兵位頭結(jié)點本身是沒有數(shù)據(jù)的,所以要從下一個結(jié)點開始
void test1()
{
wxd::list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
lt1.print();
}
也是沒有任何問題的
7,_list_iterator
迭代器的框架和初始化
template<class T,class ref,class ptr>
struct _list_iterator
{
typedef list_node<T> node;
typedef _list_iterator<T,ref,ptr> sefl;
node* _node;
_list_iterator(node* n)
:_node(n)
{}
}
有人會好奇,為什么模板里面有三個參數(shù),現(xiàn)在先不急下面會進行分曉的;
指向結(jié)點的迭代器嘛,底層類型就是指針;
初始化也是一樣,傳來什么就是什么;
8,operator*()
迭代器解引用取值
ref operator*()
{
return _node->data;
}
ref 其實就是 T&;
9,begin()
找頭結(jié)點
iterator begin()
{
return iterator(_head->_next);
}
直接返回構(gòu)造完后的結(jié)果;
10,end()
最后一個結(jié)點的下一個位置
iterator end()
{
return iterator(_head);
}
然后我們就可以試一下迭代器打印了;
void print_list(const list<int>& lt)
{
list<int>::const_iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test1()
{
wxd::list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
print_list(lt1);
}
11,operator->()
迭代器箭頭指向取值
ptr operator->()
{
return &_node->data;
}
返回的是 data 的地址,ptr 是 T* ;
12,operator++()
迭代器前置++
sefl& operator++()
{
_node = _node->_next;
return *this;
}
sefl 是??_list_iterator<T,ref,ptr>;
13,operator++(int)
迭代器后置++
sefl operator++(int)
{
sefl tmp(*this);
_node = _node->_next;
return tmp;
}
返回的是之前的值,但其實已經(jīng)改變了;
14,operator--()
迭代器前置 - -
sefl& operator--()
{
_node = _node->_prev;
return *this;
}
15,operator--(int)
迭代器后置 - -
sefl operator--(int)
{
sefl tmp(*this);
_node = _node->_prev;
return tmp;
}
16,operator==(const sefl& s)
迭代器判斷相等
bool operator==(const sefl& s)
{
return _node == s._node;
}
判斷迭代器是否相等比較 _node 就可以了;
17,operator!=(const sefl& s)
判斷是否不相等
bool operator!=(const sefl& s)
{
return _node != s._node;
}
18,_list_const_iterator
然后這個是 const 迭代器版本的,這里我就不一個一個寫了;
template<class T>
struct _list_const_iterator
{
typedef list_node<T> node;
typedef _list_const_iterator<T> sefl;
node* _node;
_list_const_iterator(node* n)
:_node(n)
{}
const T& operator*()
{
return _node->data;
}
sefl& operator++()
{
_node = _node->_next;
return *this;
}
sefl operator++(int)
{
sefl tmp(*this);
_node = _node->_next;
return tmp;
}
sefl& operator--()
{
_node = _node->_prev;
return *this;
}
sefl operator--(int)
{
sefl tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator==(const sefl& s)
{
return _node == s._node;
}
bool operator!=(const sefl& s)
{
return _node != s._node;
}
};
其實吧,_list_const_iterator 跟?_list_iterator 就是內(nèi)部函數(shù)參數(shù)的返回值不同罷了,我們可以用模板參數(shù)來實例化,這樣就不用寫兩個迭代器了;
template <class T>
class list
{
typedef list_node<T> node;
public:
typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T, const T&, const T*> const_iterator;
在 list 下面這樣操作就可以了,普通迭代器模板一個版本,const 迭代器模板內(nèi)的參數(shù)加上const就可以了,等調(diào)用的時候編譯器會自動匹配的;
19,list(iterator first, iterator last)
迭代器區(qū)間構(gòu)造
template<class iterator>
list(iterator first, iterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
20,begin()const
const 版本取頭結(jié)點
const_iterator begin()const
{
return const_iterator(_head->_next);
}
21,end()const
const 版本取尾結(jié)點的下一個位置
const_iterator end()const
{
return const_iterator(_head);
}
22,list(const list<T>& lt)
拷貝構(gòu)造
void swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
list(const list<T>& lt)
{
empty_init();
list<T> tmp(lt.begin(), lt.end());
swap(tmp);
}
先把要拷貝的區(qū)間信息構(gòu)造另一個 list ,然后再與 this 指針的 _head哨兵位頭結(jié)點進行交換即可;
23,operator=(list<T> lt)
賦值
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
24,insert(iterator pos, const T& x)
插入
void insert(iterator pos, const T& x)
{
node* cur = pos._node;
node* prev = cur->_prev;
node* newnode = new node(x);
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
}
定義前一個結(jié)點,和本身的結(jié)點,然后再進行插入即可;
void test3()
{
wxd::list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
auto pos = find(lt1.begin(), lt1.end(), 3);
lt1.insert(pos, 9);
print_list(lt1);
}
25,erase(iterator pos)
擦除
iterator erase(iterator pos)
{
assert(pos != end());
node* next = pos._node->_next;
node* tail = pos._node->_prev;
tail->_next = next;
next->_prev = tail;
delete pos._node;
return iterator(next);
}
先斷言一下,哨兵位結(jié)點是不能擦除的;
然后找到前一個結(jié)點,后一個結(jié)點,在進行互相綁定;
在釋放要刪除的空間;
26,clear()
清除
void clear()
{
auto it = begin();
while (it != end())
{
it=erase(it);
}
}
27,~list()
析構(gòu)函數(shù)
~list()
{
clear();
delete _head;
_head = nullptr;
}
先清空結(jié)點,然后再是否哨兵位頭結(jié)點置空即可;
28,push_front(const T& x)
頭插
void push_front(const T& x)
{
insert(begin(), x);
}
直接用 insert 插入更加方便;
29,pop_front()
頭刪
void pop_front()
{
erase(begin());
}
30,pop_back()
尾刪
void pop_back()
{
erase(_head->_prev);
}
31,源代碼
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
struct list_node
{
list_node<T>* _next;
list_node<T>* _prev;
T data;
list_node(const T& x = T())
:_next(nullptr)
, _prev(nullptr)
, data(x)
{}
};
template<class T,class ref,class ptr>
struct _list_iterator
{
typedef list_node<T> node;
typedef _list_iterator<T,ref,ptr> sefl;
node* _node;
_list_iterator(node* n)
:_node(n)
{}
ref operator*()
{
return _node->data;
}
ptr operator->()
{
return &_node->data;
}
sefl& operator++()
{
_node = _node->_next;
return *this;
}
sefl operator++(int)
{
sefl tmp(*this);
_node = _node->_next;
return tmp;
}
sefl& operator--()
{
_node = _node->_prev;
return *this;
}
sefl operator--(int)
{
sefl tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator==(const sefl& s)
{
return _node == s._node;
}
bool operator!=(const sefl& s)
{
return _node != s._node;
}
};
template <class T>
class list
{
typedef list_node<T> node;
public:
typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T, const T&, const T*> const_iterator;
void empty_init()
{
_head = new node;
_head->_next = _head;
_head->_prev = _head;
}
list()
{
empty_init();
}
template<class iterator>
list(iterator first, iterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
void push_back(const T& x)
{
node* tail = _head->_prev;
node* newnode = new node(x);
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}
iterator begin()
{
return iterator(_head->_next);
}
const_iterator begin()const
{
return const_iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator end()const
{
return const_iterator(_head);
}
void swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
list(const list<T>& lt)
{
empty_init();
list<T> tmp(lt.begin(), lt.end());
swap(tmp);
}
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
void insert(iterator pos, const T& x)
{
node* cur = pos._node;
node* prev = cur->_prev;
node* newnode = new node(x);
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
}
iterator erase(iterator pos)
{
assert(pos != end());
node* next = pos._node->_next;
node* tail = pos._node->_prev;
tail->_next = next;
next->_prev = tail;
delete pos._node;
return iterator(next);
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
void clear()
{
auto it = begin();
while (it != end())
{
it=erase(it);
}
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_back()
{
erase(_head->_prev);
}
void pop_front()
{
erase(begin());
}
void print()
{
node* cur = _head->_next;
while (cur != _head)
{
cout << cur->data << " ";
cur = cur->_next;
}
}
private:
node* _head;
};
32,總結(jié)
我們就先搞一個大概的,其中還有很多分支,比如我們寫的是擦除某個數(shù)據(jù),其實也可以擦除某個范圍,這些就靠大家去摸索,查閱文檔了;
list 類的實現(xiàn)就到這里了;
加油!文章來源:http://www.zghlxwxcb.cn/news/detail-785361.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-785361.html
到了這里,關(guān)于【C++】手撕 list類(包含迭代器)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!