C++ 实现链表

使用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;
}

在这里插入图片描述

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平面海螺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值