list的相關介紹
- ?list是可以在常數范圍內在任意位置進行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。
- ?list的底層是帶頭雙向循環鏈表結構,鏈表中每個元素存儲在互不相關的獨立節點中,在節點中通過指針指向其前一個元素和后一個元素。
- ?list與forward_list非常相似:最主要的不同在于forward_list是單鏈表,只能朝前迭代,已讓其更簡單高效。
- 與其他的序列式容器相比(array,vector,deque),list通常在任意位置進行插入、移除元素的執行效率更好。
- list需要一些額外的空間,以保存每個節點的相關聯信息(對于存儲類型較小元素的大list來說這可能是一個重要的因素)
想要了解更多關于list的詳細內容,請點擊list的文檔介紹。
list的使用
注意:本章只介紹一些常用的接口
list的構造
構造函數 | 接口說明 | 代碼演示 |
list() | 構造空的list | list<int> l1; |
list(size_t n, const T& val = T()) | 構造的list中包含n個值為val的元素 | list<int> l2(5, 100); // l2中放5個值為100的元素 |
list(const list<T>& x) | 拷貝構造函數 | list<int> l3(l2); |
list(InputIterator first, InputIterator last) | 用[first, last)區間中的元素構造list | list<int> l4(l2.begin(), l2.end()); |
list(initializer_list<T> li) | 使用花括號進行構造(C++11) | list<int> lt = { 1,2,3,4,5 }; |
list iterator的使用
list的迭代器,大家在這里可以暫時理解成一個指針,該指針指向list的某個節點。
函數說明 | 接口說明 |
begin + end | 返回第一個元素的迭代器+返回最后一個元素下一個位置的迭代器 |
rbegin + rend | 返回第一個元素的reverse_iterator,即end位置,返回最后一個元素下一個位置的reverse_iterator,即begin位置 |
// 迭代器使用舉例
int main()
{list<int> li = {1,2,3,4};list<int>::iterator it = li.begin();while (it != li.end()){cout << *it << " ";++it;}return 0;
}
list的增刪查改
函數聲明 | 接口說明 | 代碼演示 |
insert | 在list pos 位置中插入值為val的元素 | iterator insert(iterator pos, const T& val) |
erase | 刪除list pos 位置的元素 | iterator erase(iterator pos) |
clear | 清空list的有效元素 | void clear() |
注意:在list的接口里面沒有提供[ ],因為效率不高
list的迭代器失效
相比vector,list的迭代器失效相對簡單一些。
前面說過,此處大家可將迭代器暫時理解成類似于指針,迭代器失效 即迭代器所指向的節點已經不存在了,即該節點被刪除了。因為list的底層結構為帶頭雙向循環鏈表,因此在list中進行插入時是不會導致list的迭代器失效的,只有在刪除時才會失效,并且失效的只是指向被刪除節點的迭代器,其他迭代器不會受到影響。
// 刪除是偶數的數據
list<int> li = {1,2,3,4};
list<int>::iterator it = li.begin();
while (it != li.end())
{if (*it % 2 == 0)//li.erase(it); 會導致迭代器失效it = li.erase(it); //重新對迭代器進行賦值,就會避免失效的問題else++it;
}
注意:此處的迭代器失效只是針對vs下所說,不同平臺的list底層實現結構不同,所以在其他平臺下可能不會失效?
list的底層實現
迭代器的實現
與vector不同,vector的迭代器使用原生態指針就可以搞定,但list不行,因為list的底層結構是不連續的,所以對list的原生態指針進行了封裝。
template<class T, class Ref, class Ptr>
//使用一個類封裝原生態指針
struct listiterator
{typedef ListNode<T> Node;typedef listiterator<T, Ref, Ptr> Self;listiterator(Node* node) //構造:_node(node){}Self& operator++() //前置++底層結構{_node = _node->_next;return *this;}Self operator++(int) //后置++底層結構{Self tmp(*this);_node = _node->_next;return tmp;}Ref operator*() //operator*底層結構{return _node->_data;}bool operator!=(const Self& it){return _node != it._node;}Node* _node; //包含一個結點的指針
};
常用接口實現
//拷貝構造
list(const list<T>& x)
{empty_list(); //對list進行初始化for (const auto& e : x){push_back(e);}
}
//賦值
list<T>& operator=(list<T> x)
{swap(_head,x._head); //交換兩個list的頭節點return *this;
}
iterator insert(iterator pos, const T& val)
{Node* cur = pos._node; //獲取指向該結點的指針Node* newnode = new Node(val);Node* prev = cur->_prev;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 = cur->_next; //刪除next->_prev = prev;delete cur;return iterator(next);
}
void clear() //清空list的有效數據
{list<T>::iterator it = begin();while (it != end()){it = erase(it); //給迭代器重新賦值,防止迭代器失效}
}