在该部分我们将会实现C++中的list,如果对list相关知识不太了解,可以看一下之前总结过list的相关知识:C++容器:list
函数名 | 功能 |
---|---|
list() |
构造函数 |
~list() |
析构函数 |
list(const list& li) |
拷贝构造函数 |
list& operator=(const list& li) |
赋值运算符重载函数 |
void push_back(value_type val) |
向list对象尾部增添元素 |
void pop_back() |
删除list对象最后一个元素 |
void push_front(const_reference val) |
向list对象头部增添元素 |
void pop_front() |
删除list对象第一个元素 |
data_type front()const |
取出list对象中的第一个元素 |
data_type back()const |
取出list对象中的最后一个元素 |
iterator begin() |
获取list实例化对象的元素首地址 |
iterator end() |
获取list实例化对象的最后一个元素的下一个地址 |
size_t size()const |
获取list实例化对象的元素个数 |
bool empty() const |
判断list实例化对象是否为空 |
void clear() |
清空list中的元素 |
首先为了实现list可以实例化任意数据类型的对象,我们需要对它进行模板化,在类的定义之前增加如下语句:
template<typename T>
如我们想要实例化一个int
型list的时候,使用list
,此时模板中的T
就是指int
型数据类型,那么T*
就是指int*
数据类型。
我们可以在类中给这些和T相关的类型使用typedef
起别名,代码如下:
public:
typedef T data_type;
typedef size_t size_type;
typedef T& refernce;
typedef T* pointer;
typedef const T& const_reference;
typedef const T* const_pointer;
list本质上其实就是我们链表,以下就是我们实现list所用到的成员变量:
- node: 节点,一个结构体,用于存放数据
- _head: 头指针,指向list中的第一个节点
- _tail : 尾指针,指向list中的最后一个节点
- _size: list对象中的含有数据的节点个数
该部分相关代码如下:
private:
struct node{ // 嵌套类结构体
data_type data;
node* _next;
node* _prev;
node():_next(NULL), _prev(NULL) {}
};
node* _head;
node* _tail;
size_type _size;
容器的迭代器用于遍历容器中的每一个元素,同时避免容器的内部数据结构和实现细节。迭代器的意义就是将容器与算法解除耦合,或者说是让数据与操作解除耦合。算法可以利用迭代器作为输入从而摆脱对容器具体数据的访问。
我们主要讲解一下关于对于迭代器it
,自加和自减的具体实现,以前缀和后缀为两类。对于前缀即++it, --it
,该表达式的值和it的值保持统一,我们直接改变该结点_cur
的指向,返回this
指针即可;但是对于后缀it++, it--
,表达式的值是未改变前it的值,it将会进行更新,故而我们需要将_cur
的值保存进一个临时变量,再更新_cur
,返回临时变量。在实现的过程中,函数名中的圆括弧中有int
的为后缀加减。
具体实现如下:
class iterator {
node* _cur;
public:
iterator(node* cur):_cur(cur){}
data_type& operator*(){
return _cur->data;
}
data_type* operator->(){
return &_cur->data;
}
iterator operator++(){
_cur = _cur->_next;
return *this;
}
iterator operator--(){
_cur = _cur->_prev;
return *this;
}
iterator operator++(int){
iterator temp(_cur);
_cur = _cur->_next;
return temp;
}
iterator operator--(int){
iterator temp(_cur);
_cur = _cur->_prev;
return temp;
}
bool operator==(const iterator& it)const{
return _cur == it._cur;
}
bool operator!=(const iterator& it)const{
return _cur != it._cur;
}
};
我们在对list对象进行初始化的时候增加一个temp节点,使得链表的处理更加的简单统一。
list(): _size(0){
_head = _tail = new node;
}
这一部分主要涉及双向链表的插入和删除问题,指针改向的顺序需要注意,如果顺序错误,就会挂链失败。
头插具体过程如图所示:下图第一个节点是temp节点,我们进行头插的时候将新的节点挂在该结点和下一个节点中间即可。
代码如下:
void push_front(const_reference val) {
node* cur = new node;
cur->data = val;
cur->_next = _head->_next;
cur->_prev = _head;
if(NULL == _head->_next) _tail = cur;
else _head->_next->_prev = cur;
_head->_next = cur;
++_size;
}
头删具体过程如图所示:图第一个节点是temp节点,我们进行头删的时候删除的是该结点的下一个节点。
void pop_front() {
if(empty()) return;
node* first = _head->_next;
_head->_next = first->_next;
if(NULL == first->_next) _tail = _head;
else first->_next->_prev = _head;
delete first;
--_size;
}
具体过程如图所示:
代码如下:
void push_back(const_reference val){
node* cur = new node;
cur->data = val;
cur->_next = NULL;
cur->_prev = _tail;
_tail->_next = cur;
_tail = cur;
++_size;
}
void pop_back() {
if(empty()) return;
node* _prev = _tail->_prev;
delete _tail;
_prev->_next = NULL;
_tail = _prev;
--_size;
}
#include
using namespace std;
namespace miniSTL{
template<typename T>
class list{
public:
typedef T data_type;
typedef size_t size_type;
typedef T& refernce;
typedef T* pointer;
typedef const T& const_reference;
typedef const T* const_pointer;
private:
struct node{ // 嵌套类结构体
data_type data;
node* _next;
node* _prev;
node():_next(NULL), _prev(NULL) {}
};
node* _head;
node* _tail;
size_type _size;
public:
list(): _size(0){
_head = _tail = new node;
}
list(const list& li){
_head = _tail = new node;
node* p = li._head->_next;
while(p!=NULL){
push_back(p->data);
p = p->_next;
}
}
list& operator=(const list& li){
if(this == &li) return *this;
clear();
node* p = li._head->_next;
while(p!=NULL){
push_back(p->data);
p = p->_next;
}
return *this;
}
void clear(){
node* p = _head->_next;
while(p!=NULL){
node* del = p;
p = p->_next;
delete del;
}
_tail = _head;
_size = 0;
}
~list(){
node* p = _head;
while(p!= NULL){
node* del = p;
p = p->_next;
delete del;
}
_size = 0;
}
size_type size() const { return _size; }
bool empty() const { return _size == 0; }
data_type front()const{ return _head->_next->data; }
data_type back()const{ return _tail->data;}
void push_back(const_reference val){
node* cur = new node;
cur->data = val;
cur->_next = NULL;
cur->_prev = _tail;
_tail->_next = cur;
_tail = cur;
++_size;
}
void pop_back() {
if(empty()) return;
node* _prev = _tail->_prev;
delete _tail;
_prev->_next = NULL;
_tail = _prev;
--_size;
}
void push_front(const_reference val) {
node* cur = new node;
cur->data = val;
cur->_next = _head->_next;
cur->_prev = _head;
if(NULL == _head->_next) _tail = cur;
else _head->_next->_prev = cur;
_head->_next = cur;
++_size;
}
void pop_front() {
if(empty()) return;
node* first = _head->_next;
_head->_next = first->_next;
if(NULL == first->_next) _tail = _head;
else first->_next->_prev = _head;
delete first;
--_size;
}
void Print()const{
node* p = _head->_next;
while(NULL != p){
cout << p->data << " ";
p = p->_next;
}
cout << endl;
p = _tail;
while(_head!= p){
cout << p->data << " ";
p = p->_prev;
}
cout << endl;
}
// 迭代器
class iterator {
node* _cur;
public:
iterator(node* cur):_cur(cur){}
data_type& operator*(){
return _cur->data;
}
data_type* operator->(){
return &_cur->data;
}
iterator operator++(){
_cur = _cur->_next;
return *this;
}
iterator operator--(){
_cur = _cur->_prev;
return *this;
}
iterator operator++(int){
iterator temp(_cur);
_cur = _cur->_next;
return temp;
}
iterator operator--(int){
iterator temp(_cur);
_cur = _cur->_prev;
return temp;
}
bool operator==(const iterator& it)const{
return _cur == it._cur;
}
bool operator!=(const iterator& it)const{
return _cur != it._cur;
}
};
iterator begin(){
return iterator(_head->_next);
}
iterator end(){
return iterator(_tail->_next);
}
};
}
using namespace miniSTL;
int main(){
list<string> li;
string n;
while(cin >> n){
// li.push_back(n);
li.push_front(n);
}
list<string>::iterator it = li.begin();
// cout << (it->data) << endl;
while(it!=li.end()){
cout << *it << " ";
++it;
}
cout << endl;
for(auto n:li){
cout << n << " ";
}
cout << endl;
list<string> li2 = li;
list<string> li3;
li3 = li;
for(auto n:li3){
cout << n << " ";
}
cout << endl;
/*
li.Print();
while(!li.empty()){
// li.pop_front();
li.pop_back();
li.Print();
}
*/
}