List
- 1.List介绍
- 2.使用注意
- 3.list与vector的对比
- 4.练习题
1.List介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
List:帮助文档
相关接口函数可以查看帮助文档,这里主要介绍一下关键点。
2.使用注意
- end()迭代器:返回的是最后一个元素的下一位置。
- 迭代器失效问题
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
3.list与vector的对比
vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:
4.练习题
第 1 题(单选题)
题目名称:
下面有关vector和list的区别,描述错误的是(**D** )
题目内容:
**A** .vector拥有一段连续的内存空间,因此支持随机存取,如果需要高效的随机存取,应该使用vector
**B** .list拥有一段不连续的内存空间,如果需要大量的插入和删除,应该使用list
**C** .vector<int>::iterator支持“+”、“+=”、“<”等操作符
**D** .list<int>::iterator则不支持“+”、“+=”、“<”等操作符运算,但是支持了[ ]运算符
第 2 题(单选题)
题目名称:
以下程序输出结果为( )
int main(**C**)
{
int ar[] = { 0,1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = sizeof(ar) / sizeof(int);
list<int> mylist(ar, ar+n);
list<int>::iterator pos = find(mylist.begin(), mylist.end(), 5);
reverse(mylist.begin(), pos);
reverse(pos, mylist.end());
list<int>::const_reverse_iterator crit = mylist.crbegin();
while(crit != mylist.crend())
{
cout<<*crit<<" ";
++crit;
}
cout<<endl;
}
题目内容:
**A** .4 3 2 1 0 5 6 7 8 9
**B** .0 1 2 3 4 9 8 7 6 5
**C** .5 6 7 8 9 0 1 2 3 4
**D** .5 6 7 8 9 4 3 2 1 0
第 3 题(单选题)
题目名称:
以下代码实现了从表中删除重复项的功能,请选择其中空白行应填入的正确代码(**B** )
template<typename T>
void removeDuplicates(list<T> &aList)
{
T curValue;
list<T>::iterator cur, p;
cur = aList.begin();
while (cur != aList.end())
{
curValue = *cur;
//空白行 1
while (p != aList.end())
{
if (*p == curValue)
{
//空白行 2
}
else
{
p++;
}
}
}
}
题目内容:
**A** . p=cur+1;aList.erase(p++);
**B** .p=++cur; p == cur ? cur = p = aList.erase(p) : p = aList.erase(p);
**C** .p=cur+1;aList.erase(p);
**D** .p=++cur;aList.erase(p);
第 4 题(编程题)
题目名称:
list的增删查改的模拟实现
题目内容:
模拟实现list类,并完成测试
namespace bite
{
// List的节点类
template<class T>
struct ListNode
{
ListNode(const T& val = T());
ListNode<T>* _pPre;
ListNode<T>* _pNext;
T _val;
};
//List的迭代器类
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr);
ListIterator(const Self& l);
T& operator*();
T* operator->();
Self& operator++();
Self operator++(int);
Self& operator--();
Self& operator--(int);
bool operator!=(const Self& l);
bool operator==(const Self& l);
private:
PNode _pNode;
};
//list类
template<class T>
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T&> const_iterator;
public:
///
// List的构造
list();
list(int n, const T& value = T());
template <class Iterator>
list(Iterator first, Iterator last);
list(const list<T>& l);
list<T>& operator=(const list<T> l);
~list();
///
// List Iterator
iterator begin();
iterator end();
const_iterator begin();
const_iterator end();
///
// List Capacity
size_t size()const;
bool empty()const;
// List Access
T& front();
const T& front()const;
T& back();
const T& back()const;
// List Modify
void push_back(const T& val){insert(begin(), val);}
void pop_back(){erase(--end());}
void push_front(const T& val){insert(begin(), val);}
void pop_front(){erase(begin());}
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val);
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos);
void clear();
void swap(List<T>& l);
private:
void CreateHead();
PNode _pHead;
};
};
第 1 题(单选题)
题目名称:
下面程序的输出结果正确的是(**B** )
int main()
{
int array[] = { 1, 2, 3, 4, 0, 5, 6, 7, 8, 9 };
int n = sizeof(array) / sizeof(int);
list<int> mylist(array, array+n);
auto it = mylist.begin();
while (it != mylist.end())
{
if(* it != 0)
cout<<* it<<" ";
else
it = mylist.erase(it);
++it;
}
return 0;
}
//这里it==5 erase之后指向下一个元素的迭代器
**改造一下保留5**
```c++
int array[] = { 1, 2, 3, 4, 0, 5, 6, 7, 8, 9 };
int n = sizeof(array) / sizeof(int);
list<int> mylist(array, array + n);
auto it = mylist.begin();
while (it != mylist.end())
{
if (*it != 0)
{
cout << *it << " ";
++it;
}
else
it = mylist.erase(it);//这里it==5 erase之后指向下一个元素的迭代器
}
题目内容:
A .1 2 3 4 5 6 7 8 9
B . 1 2 3 4 6 7 8 9
C .程序运行崩溃
D .1 2 3 4 0 5 6 7 8 9
第 2 题(单选题)
题目名称:
对于list有迭代器it, 当erase(it)后,说法错误的是(C )
题目内容:
A .当前迭代器it失效
B .it前面的迭代器仍然有效
C .it后面的迭代器失效
D .it后面的迭代器仍然有效
第 3 题(单选题)
题目名称:
下面有关vector和list的区别,描述错误的是( D)
题目内容:
A .vector拥有一段连续的内存空间,因此支持随机存取,如果需要高效的随机读取,应该使用vector
B .list拥有一段不连续的内存空间,如果需要大量的插入和删除,应该使用list
C .vector::iterator支持“+”、“+=”、“<”等操作符
D .list::iterator则不支持“+”、“+=”、“<”等操作符运算,但是支持了[]运算符
第 4 题(单选题)
题目名称:
下面有关vector和list的区别,描述正确的是( A)
题目内容:
A .两者在尾部插入的效率一样高
B .两者在头部插入的效率一样高
C .两者都提供了push_back和push_front方法
D .两者都提供了迭代器,且迭代器都支持随机访问