網站首頁 編程語言 正文
一、基本結構
由源代碼可知,list容器是有一個帶頭雙向循環鏈表實現,所以我們模擬實現也需要實現一個帶頭雙向循環鏈表的數據結構。
template<class T>
struct list_node
{
list_node<T>* _next;
list_node<T>* _prev;
T _data;
list_node(const T& val = T())//用一個匿名對象來做缺省參數
:_next(nullptr)
, _prev(nullptr)
, _data(val)
{}
};
template<class T>
class list
{
public:
typedef list_node<T> Node;
private:
Node* _head;
};
二、list的迭代器的構造
list的迭代器與vector的迭代器不一樣,list的迭代器是一個自定義類型的對象,成員變量包含一個指向節點的指針。
template<class T, class Ref, class Ptr>
struct __list_iterator
{
typedef list_node<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
Node* _node;
__list_iterator(Node* node)
:_node(node)
{}
// 析構函數 -- 節點不屬于迭代器,不需要迭代器釋放
// 拷貝構造和賦值重載 -- 默認生成的淺拷貝就可以
// *it
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
//return &(operator*());
return &_node->_data;
}
self& operator++()
{
_node = _node->_next;
return *this;
}
self operator++(int)
{
self tmp(*this);//拷貝構造
_node = _node->_next;
return tmp;//因為tmp出了作用域就不在了,所以不可以引用返回
}
self& operator--()
{
_node = _node->_prev;
return *this;
}
self operator--(int)
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
??????即用一個自定義類型封裝,通過運算符的重載使迭代器實現像指針一樣的操作行為。
三、迭代器的實現
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_iterator<T, const T&, const T*> begin() const
{
// list_node<int>*
return __list_iterator<T, const T&, const T*>(_head->_next);
//構造一個匿名對象
}
const_iterator end() const
{
return const_iterator(_head);
}
iterator begin()
{
return iterator(_head->_next);//構造一個匿名對象來返回
//return _head->_next;//也可以,因為單參數構造函數支持隱式類型轉換。
//iterator it = _head->_next 隱式調用
}
iterator end()
{
return iterator(_head);
}
}
四、insert,erase
// 插入在pos位置之前
iterator insert(iterator pos, const T& x)//pos是一個迭代器對象
{
Node* newNode = new Node(x);
Node* cur = pos._node;
Node* prev = cur->_prev;
// prev newnode cur
prev->_next = newNode;
newNode->_prev = prev;
newNode->_next = cur;
cur->_prev = newNode;
return iterator(newNode);
}
iterator erase(iterator pos)
{
assert(pos != end());
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
// prev next
prev->_next = next;
next->_prev = prev;
delete cur;
return iterator(next);
}
五、push_back,push_front,pop_back,pop_front
void push_back(const T& x)
{
//Node* tail = _head->_prev;
//Node* newnode = new Node(x);
_head tail newnode
//tail->_next = newnode;
//newnode->_prev = tail;
//newnode->_next = _head;
//_head->_prev = newnode;
insert(end(), x);
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_back()
{
erase(--end());
//這里不可以用end()-1吧,因為尾部迭代器在尾刪后是需要變得
}
void pop_front()
{
erase(begin());
}
??這里均復用了insert和erase函數。
六、構造函數與賦值重載
list()//帶頭雙向循環鏈表,初始化要先把頭弄出來
{
_head = new Node();
//自定義類型去調用對應類的構造函數,帶不帶這個括號都可
_head->_next = _head;
_head->_prev = _head;
}
// lt2(lt1)————傳統寫法
/*list(const list<T>& lt)
{
_head = new Node();
_head->_next = _head;
_head->_prev = _head;
for (auto e : lt)
{
push_back(e);//push_back中復用insert,insert中完成深拷貝
}
}*/
void empty_init()
{
_head = new Node();
_head->_next = _head;
_head->_prev = _head;
}
//如果我們寫現代寫法,那么必須提供相應的帶參構造
template <class InputIterator>
list(InputIterator first, InputIterator last)
{
empty_init();
while (first != last)
{
push_back(*first);//push_back中調用insert時會完成相應深拷貝
++first;
}
}
void swap(list<T>& lt)
{
std::swap(_head, lt._head);//交換頭節點
}
// lt2(lt1) -- 現代寫法
list(const list<T>& lt)
{
empty_init();//總不能把一個野指針換給別人呀!
list<T> tmp(lt.begin(), lt.end());
swap(tmp);
}
// lt2 = lt1
list<T>& operator=(list<T> lt)
//list<T> lt = lt1,傳值傳參這一步就調用了拷貝構造完成深拷貝
{
swap(lt);
return *this;
}
??????注意現代寫法的方法
七、析構與清空
~list()
{
clear();
delete _head;
_head = nullptr;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);//用返回值更新,防止迭代器失效
}
}
原文鏈接:https://blog.csdn.net/qq_43727529/article/details/125876218
相關推薦
- 2022-04-15 python實現購物車功能_python
- 2023-11-15 Latex解決表格過寬問題,自適應調整寬度;自動調整適合的表格大小
- 2022-09-30 C#?使用com獲取Windows攝像頭列表_C#教程
- 2022-11-19 Python+random模塊實現隨機抽樣_python
- 2022-03-22 C++實現轉置矩陣的循環(矩陣轉置函數)
- 2023-06-18 C#實現不同窗體之間傳遞參數_C#教程
- 2022-04-20 Python統計節假日剩余天數的腳本_python
- 2022-08-19 vscode遠程免密登入Linux服務器的配置方法_Linux
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支