使用C++编写一个类模板,实现链表的功能,可以插入、删除、查找结点、在末尾添加新结点、遍历链表、翻转链表和连接两个链表,并重载了数组下标运算符、拷贝构造函数、移动构造函数、拷贝赋值运算符和移动赋值运算符。该类的数据成员有头结点、尾结点、链表长度和结点类型。
List.hpp
#ifndef LIST_H
#define LIST_H
template<typename T>
class List {
public:
List();
List(const List& src);
List(List&& src)noexcept;
List& operator=(const List& rhs);
List& operator=(List&& rhs)noexcept;
T operator[](const size_t& index);
~List();
public:
using LISTNODE = struct listNode {
T element{};
listNode* next{};
};
LISTNODE* m_head{};//头指针
LISTNODE* m_rear{};//尾指针
size_t m_length{};//链表长度
public:
LISTNODE* initList(T values[], size_t length);//使用数组初始化
LISTNODE* append(const T& value);//在末尾添加
std::unique_ptr<T[]> traverse();//遍历
LISTNODE* at(const size_t& index);//获取结点
LISTNODE* insert(const size_t& loc, const T& value);
T erase(const size_t& loc);
LISTNODE* reverse();
LISTNODE* link(List& list);
};
//默认构造函数
template<typename T>
inline List<T>::List(){
m_length = 0;
m_head = new LISTNODE;
m_rear = m_head;
}
//拷贝构造函数
template<typename T>
List<T>::List(const List& src) :List{} {
m_length = src.m_length;
m_head = new LISTNODE;
m_head->element = src.m_head->element;//拷贝头结点
decltype(m_head) p1{ m_head };//头节点
decltype(m_head) p2{ src.m_head->next };//首节点
while (p2 != nullptr) {
p1->next = new LISTNODE;
p1 = p1->next;
p1->element = p2->element;
p2 = p2->next;
m_rear = p1;
}
}
//移动构造函数
template<typename T>
List<T>::List(List&& src)noexcept {
m_head = src.m_head;
m_rear = src.m_rear;
m_length = src.m_length;
src.m_head = nullptr;
src.m_rear = nullptr;
src.m_length = 0;
}
//拷贝赋值运算符
template<typename T>
List<T>& List<T>::operator=(const List& rhs) {
if (this == &rhs)return *this;
m_length = rhs.m_length;
while (m_head != nullptr) {
auto p{ m_head->next };
delete m_head;
m_head = p;
}//释放原来的结点
m_head = new LISTNODE;
m_head->element = rhs.m_head->element;//拷贝头结点
auto p1{ m_head };//头节点
auto p2{ rhs.m_head->next };
while (p2 != nullptr) {
p1->next = new LISTNODE;
p1 = p1->next;
p1->element = p2->element;
p2 = p2->next;
m_rear = p1;
}
return *this;
}
//移动赋值运算符
template<typename T>
List<T>& List<T>::operator=(List&& rhs)noexcept {
if (this == &rhs)return *this;
//释放原对象的内存
while (m_head != nullptr) {
auto p = m_head->next;
delete m_head;
m_head = p;
}
m_head = rhs.m_head;
m_rear = rhs.m_rear;
m_length = rhs.m_length;
rhs.m_head = nullptr;
rhs.m_rear = nullptr;
rhs.m_length = 0;
return *this;
}
//重载数组下标
template<typename T>
inline T List<T>::operator[](const size_t& index){
if (index < 0 || index>m_length - 1) { return T(); }
auto p{ m_head };
for (int i{}; i <= index; i++) {
p = p->next;
}
return p->element;
}
//析构函数
template<typename T>
List<T>::~List() {
decltype(m_head) p{ m_head };//头结点也要释放
decltype(m_head) temp{ nullptr };
while (p != nullptr) {
temp = p->next;
delete p;
p = temp;
}
}
//使用数组初始化(当链表对象创建在自由存储区时才能使用此方法!)
template<typename T>
typename List<T>::LISTNODE* List<T>::initList(T values[], size_t length) {
if (m_length != 0)return m_head;//链表长度不为0时不应该使用此方法
LISTNODE* nodes = new LISTNODE[length]{};//这块内存需要用delete[]才能正确释放
for (int i{ 0 }; i < length; ++i) {
nodes[i].element = values[i];
nodes[i].next = &nodes[i + 1];
}
m_head->next = &nodes[0];
m_rear = &nodes[length - 1];
m_rear->next = nullptr;
m_length = length;
return m_head;
}
//在末尾添加一个新结点
template<typename T>
typename List<T>::LISTNODE* List<T>::append(const T& value) {
m_rear->next = new LISTNODE;
m_rear = m_rear->next;
m_rear->element = value;
m_length++;
return m_rear;
}
//遍历链表
template<typename T>
std::unique_ptr<T[]> List<T>::traverse() {
T* res{ new T[m_length] };//保存遍历结果的数组
std::unique_ptr<T[]> resPtr{ res };//指向数组的智能指针
auto p{ m_head->next };//首结点
for (int i{ 0 }; i < m_length; ++i) {
resPtr[i] = p->element;
p = p->next;
}
return resPtr;
}
//查找结点
template<typename T>
inline typename List<T>::LISTNODE* List<T>::at(const size_t& index){
if (index < 0 || index>m_length - 1) { return nullptr; }
auto p{ m_head };
for (int i{}; i <= index; i++) {
p = p->next;
}
return p;
}
//插入结点
template<typename T>
inline typename List<T>::LISTNODE* List<T>::insert(const size_t& loc, const T& value){
LISTNODE* node = new LISTNODE;
node->element = value;
if (loc >= m_length) {
m_rear->next = node;
node->next = nullptr;
m_rear = node;
m_length++;
}
else {
auto prev{ m_head };
auto p{ m_head->next };
for (int i{ 0 }; i < loc; ++i) {
prev = prev->next;
p = p->next;
}
prev->next = node;
node->next = p;
m_length++;
}
return node;
}
//删除结点
template<typename T>
inline T List<T>::erase(const size_t& loc){
auto p{ m_head };
auto temp{ m_head->next->next };
if (loc >= m_length - 1) {
T res{ m_rear->element };
for (int i{ 0 }; i < m_length - 1; ++i) {
p = p->next;
}
delete m_rear;
m_rear = p;
m_rear->next = nullptr;
m_length--;
return res;
}
else {
for (int i{ 0 }; i < loc; ++i) {
p = p->next;
temp = temp->next;
}
T res{ p->next->element };
delete p->next;
p->next = temp;
m_length--;
return res;
}
}
//翻转链表
template<typename T>
inline typename List<T>::LISTNODE* List<T>::reverse(){
auto front{ m_head };
auto back{ m_head->next };
auto temp{ m_head->next };
m_head->next = m_rear;
m_rear = temp;
while (back != nullptr) {
temp= back->next;
back->next = front;
front = back;
back = temp;
}
m_rear->next = nullptr;
return m_head;
}
//连接两个链表
template<typename T>
inline typename List<T>::LISTNODE* List<T>::link(List& list){
m_rear->next = list.m_head->next;
m_rear = list.m_rear;
m_length += list.m_length;
list.m_head->next = nullptr;
list.m_rear = nullptr;
list.m_length = 0;
return m_head;
}
#endif
main.cpp
#include <memory>
#include <iostream>
#include "List.hpp"
using std::cout;
using std::cin;
using std::endl;
using std::move;
using std::string;
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
List<int> list;
list.append(8);
list.append(9);
list.append(10);
list.append(11);
list.insert(8, 12);
list.reverse();
cout << "length:" << list.m_length << endl;
auto res{ list.traverse() };
for (int i{0}; i < list.m_length; ++i) {
cout << res[i] << " ";
}
cout << endl;
List<string>* list2 = new List<string>();
string str[]{"hello","...","world","!"};
list2->initList(str, 4);
List<string> *list3{ new List<string>(*list2) };
list2->link(*list3);
delete list3;
auto res2{ list2->traverse() };
for (int i{ 0 }; i < list2->m_length; ++i) {
cout << res2[i] << " ";
}
return 0;
}