自学内容网 自学内容网

C++初阶:适合新手的手撕list(模拟实现list)

1. 基本结构与文件规划

  • list.h头文件:包含类的全部(函数的声明与定义)

  • test.cpp源文件:进行调用test函数,测试和完善功能

 基本结构:

#pragma once

namespace CH
{
//定义节点,采用struct,是因为struct的结构体是公有的
template <class T>
struct list_node
{
list_node<T>* _prve;
list_node<T>* _next;
T _val;

list_node(const T& val=T())
:_prve(nullptr)
,_next(nullptr)
,_val(val)
{
}

};


//迭代器
template <class T,class Ref,class Prt>
struct  list_iterator
{
typedef list_node<T> Node;//重命名
typedef list_iterator<T, Ref ,Prt> self;//重命名
Node* _node;//定义节点0

//构造函数
list_iterator(Node* node )//这里定义节点作为形参,因为在my_list中会传节点来初始化

Ref operator* ()//换成这个,如果调用的是const类型的,就返回const类型的,不是就返回正常类型的
Prt operator->()

//前置++
self& operator++()//返回迭代器类型

//后置++
self operator++(int)//返回迭代器类型

//前置--
self& operator--()

//后置--
self operator--(int)

bool operator!=(const self& it)

bool operator==(const self& it)
};


template <class T>
class my_list
{
typedef list_node<T> Node;
public:
typedef list_iterator<T, T& ,T*> iterator;//如果不是const类型的就调用这个
typedef list_iterator<T, const T&,const T*> const_iterator;//是const类型的调这个

        //迭代器
iterator begin()//返回迭代器类型会调用迭代器的构造函数
iterator end()
const_iterator begin()const
const_iterator end()const

//初始化,并且创造一个头节点
void empty_init()

//构造函数
my_list()

//拷贝构造
my_list(const my_list<T>& lt)

//析构函数
~my_list()


//交换
void swap(my_list<T>& lt)

//"="
my_list& operator=(my_list<T> lt)

//全部删除
void clear()

//尾插
void push_back(const T& x)

//头插
void push_front(const T& x)

//尾删
void pop_back()

//头删
void pop_front()

//插入
iterator insert(iterator pos, const T& x)//返回删除之后下一个迭代器的位置

//删除
iterator erase(iterator pos)//返回删除之后下一个迭代器的位置

//记录节点个数
size_t size()

private:
Node* _head;//定义头节点
size_t _size;//记录节点的个数
};

};

list_node 结构体:

  • 定义了链表的节点结构,包含了三个成员变量:前驱指针 _prev、后继指针 _next 和数据 _data
  • 构造函数初始化了这些成员变量,允许在创建节点时指定初始值。

my_list 类:

  • 包含了迭代器的定义、构造函数、析构函数以及一系列的操作函数。
  • 定义了两种迭代器类型:iterator 和 const_iterator,分别用于可修改的迭代和只读的迭代。
  • 实现了一系列的操作函数

2. 默认函数

2.1 构造函数

  我将私有变量初始化单独放在了一个函数中,以后初始化直接调用就行

//初始化
void empty_init()
{
_head = new Node;//开辟头节点,并且头节点不存数据
_head->_prve = _head;
_head->_next = _head;

_size = 0;
}

//空参构造函数
my_list()
{
empty_init();
}

//这也是一种构造函数
my_list(size_t n,const T& x=T())
{
    empty_init();
    for(size_t i=0;i<10;i++)
    {
         oush_back(x);
    }
}

//迭代器构造
template <class Iterator>//为什么使用模版:因为可能使用其他类型的迭代器来进行初始化
my_list(Iterator first, Iterator last)
{
    while (first != last)
    {
        push_back(*first);
        first++;
    }
}


2.2 拷贝构造

//拷贝构造
my_list(const my_list<T>& lt)
{
empty_init();
for (auto& x : lt)//这里用引用,因为自定义类型拷贝代价大
{
push_back(x);
}
}

2.3 析构函数

//析构函数
~my_list()
{
clear();
delete _head;
_head = nullptr;
}

3. 迭代器(iterator)(begin(),end())

这里为什么我们要把迭代器封装为一个类呢?明明之前模拟vectorstring时,就直接typedef

迭代器从某种程度来说也可以理解为是节点的地址,返回就是返回这个节点的地址

之前模拟vectorstring时,二者底层都是连续的,想要到下一个可以直接++;想要得到里面的数据可以直接*

但是现在对于list是不行的,我们就需要重载各种运算符,但是底层又是一个指针(内置类型)不能重载,现在就只能封装进一个类里,就能重载了

#pragma once
//#include<iostream>
//using namespace std;

namespace CH
{
//迭代器
template <class T,class Ref,class Prt>
struct  list_iterator
{
typedef list_node<T> Node;//重命名
typedef list_iterator<T, Ref ,Prt> self;//重命名
Node* _node;//定义节点0

//构造函数
list_iterator(Node* node )//这里定义节点作为形参,因为在my_list中会传节点来初始化
:_node(node)
{
}

Ref operator* ()//换成这个,如果调用的是const类型的,就返回const类型的,不是就返回正常类型的
{
return _node->_val;
}

Prt operator->()
{
return &_node->_val;
}

//前置++
self& operator++()//返回迭代器类型
{
_node = _node->_next;
return *this;
}
//后置++
self operator++(int)//返回迭代器类型
{
self tmp(*this);
            _node = _node->_next;
return tmp;
}

//前置--
self& operator--()
{
_node = _node->_prve;
return *this;
}

//后置--
self operator--(int)
{
self tmp(*this);
_node = _node->_prve;
return tmp;
}

bool operator!=(const self& it)
{
return _node != it._node;
}

bool operator==(const self& it)
{
return _node == it._node;
}

};

template <class T>
class my_list
{
typedef list_node<T> Node;
public:
typedef list_iterator<T, T& ,T*> iterator;//如果不是const类型的就调用这个
typedef list_iterator<T, const T&,const T*> const_iterator;//是const类型的调这个


iterator begin()//返回迭代器类型会调用迭代器的构造函数
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin()const
{
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
private:
Node* _head;//定义头节点
size_t _size;//记录节点的个数
};

};

4.增删改查

4.1 insert()

//插入
iterator insert(iterator pos, const T& x)//返回删除之后下一个迭代器的位置
{
Node* newnode = new Node(x);//在迭代器中找到这个位置的节点
Node* tmp = pos._node;
Node* prve = tmp->_prve;

prve->_next = newnode;
newnode->_prve = prve;

newnode->_next = tmp;
tmp->_prve = newnode;

++_size;

return newnode;
}

4.2 push_back()和push_front()

//尾插
void push_back(const T& x)
{
insert(end(), x);
}

//头插
void push_front(const T& x)
{
insert(begin(), x);
}

4.3 erase() 

//删除
iterator erase(iterator pos)//返回删除之后下一个迭代器的位置
{
Node* tmp = pos._node;//在迭代器中找到这个位置的节点
Node* prve = tmp->_prve;
Node* next = tmp->_next;

prve->_next = next;
next->_prve = prve;

delete tmp;
--_size;

return next;
}

4.3 pop_back()和pop_front()

//尾删
void pop_back()
{
erase(--end());
}

//头删
void pop_front()
{
erase(begin());
}

5. 其他函数

5.1 swap()和clear()

//交换
void swap(my_list<T>& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}

//全部删除
void clear()
{
iterator it = begin();
while (it != end())
{
it=erase(it);
}

_size = 0;
}

5.2 size()和"="

//"="
my_list& operator=(my_list<T> lt)
{
swap(lt);
return *this;
}

//节点个数
size_t size()
{
return _size;
}

7. 全部代码

list.h

#pragma once

namespace CH
{
//定义节点,采用struct,是因为struct的结构体是公有的
template <class T>
struct list_node
{
list_node<T>* _prve;
list_node<T>* _next;
T _val;

list_node(const T& val=T())
:_prve(nullptr)
,_next(nullptr)
,_val(val)
{
}

};

//迭代器
template <class T,class Ref,class Prt>
struct  list_iterator
{
typedef list_node<T> Node;//重命名
typedef list_iterator<T, Ref ,Prt> self;//重命名
Node* _node;//定义节点0

//构造函数
list_iterator(Node* node )//这里定义节点作为形参,因为在my_list中会传节点来初始化
:_node(node)
{
}

Ref operator* ()//换成这个,如果调用的是const类型的,就返回const类型的,不是就返回正常类型的
{
return _node->_val;
}

Prt operator->()
{
return &_node->_val;
}

//前置++
self& operator++()//返回迭代器类型
{
_node = _node->_next;
return *this;
}
//后置++
self operator++(int)//返回迭代器类型
{
self tmp(*this);
            _node = _node->_next;
return tmp;
}

//前置--
self& operator--()
{
_node = _node->_prve;
return *this;
}

//后置--
self operator--(int)
{
self tmp(*this);
_node = _node->_prve;
return tmp;
}

bool operator!=(const self& it)
{
return _node != it._node;
}

bool operator==(const self& it)
{
return _node == it._node;
}

};

template <class T>
class my_list
{
typedef list_node<T> Node;
public:
typedef list_iterator<T, T& ,T*> iterator;//如果不是const类型的就调用这个
typedef list_iterator<T, const T&,const T*> const_iterator;//是const类型的调这个

iterator begin()//返回迭代器类型会调用迭代器的构造函数
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin()const
{
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}

//初始化
void empty_init()
{
_head = new Node;//开辟一个节点,并且头节点不存数据
_head->_prve = _head;
_head->_next = _head;

_size = 0;
}

//构造函数,并且创造一个头节点
my_list()
{
empty_init();
}

//拷贝构造
my_list(const my_list<T>& lt)
{
empty_init();
for (auto& x : lt)
{
push_back(x);
}
}

//析构函数
~my_list()
{
clear();
delete _head;
_head = nullptr;
}

//交换
void swap(my_list<T>& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}

//"="
my_list& operator=(my_list<T> lt)
{
swap(lt);
return *this;
}

//全部删除
void clear()
{
iterator it = begin();
while (it != end())
{
it=erase(it);
}

_size = 0;
}

//尾插
void push_back(const T& x)
{
//Node* newnode = new Node(x);
//Node* tmp = _head->_prve;//找到头节点的前一个,也就是最后一个节点

//tmp->_next = newnode;
//newnode->_prve = tmp;

//newnode->_next = _head;
//_head->_prve = newnode;

//++_size;

insert(end(), x);
}

//头插
void push_front(const T& x)
{
insert(begin(), x);
}

//尾删
void pop_back()
{
erase(--end());
}

//头删
void pop_front()
{
erase(begin());
}

//插入
iterator insert(iterator pos, const T& x)//返回删除之后下一个迭代器的位置
{
Node* newnode = new Node(x);//在迭代器中找到这个位置的节点
Node* tmp = pos._node;
Node* prve = tmp->_prve;

prve->_next = newnode;
newnode->_prve = prve;

newnode->_next = tmp;
tmp->_prve = newnode;

++_size;

return newnode;
}

//删除
iterator erase(iterator pos)//返回删除之后下一个迭代器的位置
{
Node* tmp = pos._node;//在迭代器中找到这个位置的节点
Node* prve = tmp->_prve;
Node* next = tmp->_next;

prve->_next = next;
next->_prve = prve;

delete tmp;
--_size;

return next;
}

size_t size()
{
return _size;
}

private:
Node* _head;//定义头节点
size_t _size;//记录节点的个数
};
};


原文地址:https://blog.csdn.net/weixin_70067429/article/details/142450854

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!