#include <iostream>
#include <fstream>
#include <typeinfo>
#include <iomanip>
using namespace::std;
template <class T>
struct LinkNode {//链表结点定义
T data;
LinkNode<T>* link;
LinkNode(LinkNode<T>* ptr = NULL) { link = ptr; }//默认形参,结点指向空指针
LinkNode(const T& item, LinkNode<T>* ptr = NULL)//第一个参数为数据,第二个参数为结点指向的指针
{
data = item;
link = ptr;
}
};
template <class T>
class List { //单链表类定义, 不用继承也可实现
protected:
LinkNode<T>* first; //表头指针(头结点),头结点的存在使第i个结点对应下标第i个元素
public:
List() { first = new LinkNode<T>; } //默认构造函数
List(T x) { first = new LinkNode<T>(x); }//显式构造函数,指定头结点
List(List<T>& L); //复制构造函数
~List() { makeEmpty(); delete first; } //析构函数
void makeEmpty(); //将链表置为空表
int Length() const; //计算链表的长度
LinkNode<T>* getHead() const { return first; }//返回头结点的地址
LinkNode<T>* Search(T x); //搜索含x元素
LinkNode<T>* Locate(int i); //定位第i个元素
T* getData(int i, T& x) const; //取出第i元素值
void setData(int i, T x); //更新第i元素值
bool Insert(int i, T x); //在第i元素后插入
bool Remove(int i, T& x); //删除第i个元素
bool IsEmpty() const { return first->link == NULL ? true : false; }//判表空否
bool IsFull() const { return false; }
//void Sort(); //排序
void input(ifstream& in); //输入,如果文件流不为引用,显示错误
void output(); //输出
void foutput(ofstream& out);//输出到文件
void foutput1(ofstream& out, LinkNode<T>* cur);//递归顺序输出到文件
void foutput2(ofstream& out, LinkNode<T>* cur);//递归顺序逆序到文件
void reverse();//单链表的逆置
List<T>& operator = (List<T>& L);//重载赋值操作符
List<T>& combine(const List<T>& L);//单链表的合并
};
//复制构造函数
template <class T>
List<T>::List(List<T>& L) {
T value;
LinkNode<T>* srcptr = L.first();//声明一个结点遍历参数链表
LinkNode<T>* destptr = first = new LinkNode<T>;//新链表的头结点
while (srcptr->link) {//逐个复制参数链表的结点
value = srcptr->link->data;
destptr->link = new LinkNode<T>(value);
destptr = destptr->link;
srcptr = srcptr->link;
}
destptr->link = NULL;
}
//清空链表 时间复杂度:Θ (n)
template <class T>
void List<T>::makeEmpty()
{
LinkNode<T>* q;
while (first->link != NULL)//找到各个结点并删除
{
q = first->link; //保存被删结点
first->link = q->link; //从链上摘下该结点,通过头指针的link的移动来实现
delete q; //删除
}
}
//求单链表的长度时间复杂度:Θ (n)
template <class T>
int List<T> ::Length() const
{
LinkNode<T>* p = first->link;
//检测指针 p 指示第一号结点
int count = 0;
while (p != NULL) { //逐个结点检测,从头结点的下一个结点开始
p = p->link; count++;
}
return count;
}
//单链表的搜索,搜索元素x 时间复杂度:Θ (n)
template <class T>
LinkNode<T>* List<T>::Search(T x)
{ //在表中搜索含数据x的结点, 搜索成功时函数返回该结点地址; 否则返回NULL。
LinkNode<T>* current = first->link;
while (current != NULL && current->data != x) current = current->link;
//沿着链找含x结点
return current;
}
//单链表的定位 时间复杂度:Θ (i)
template <class T>
LinkNode<T>* List<T>::Locate(int i)
{ //函数返回表中第 i 个元素的地址。若i < 0或 i 超出
//表中结点个数,则返回NULL。
if (i < 0) return NULL; // i不合理
LinkNode<T>* current = first; int k = 0;
while (current != NULL && k < i)
{
current = current->link; k++;
}
return current; //返回第 i 号结点地址或NULL
};
//取结点数据
template <class T>
T* List<T>::getData(int i, T& x) const
{
if (i <= 0) return NULL;
LinkNode<T>* current = Locate(i);
return current->data;
}
//设置结点数据
template <class T>
void List<T>::setData(int i, T x)
{
if (i <= 0) return;
LinkNode<T>* current = Locate(i);
if (!current) return;
else current->data = x;
}
//输出链表 时间复杂度:Θ (n)
template <class T>
void List<T>::output()
{
LinkNode<T>* current = first->link;
while (current)
{
cout << current->data << endl;
current = current->link;
}
}
//单链表的文件输出
template <class T>
void List<T>::foutput(ofstream& out)
{
LinkNode<T>* current = first->link;
while (current)
{
out << current->data << endl;
current = current->link;
}
}
//输入链表
template <class T>
void List<T>::input(ifstream& in)
{
if (!in) {
cout << "打开文件失败" << endl;
}
int i = 0;
while (true)
{
T Data;
in >> Data;
if (in.eof()) break;
Insert(i, Data);
i++;
}
}
//赋值操作重载 时间复杂度:Θ (L.Length())
template <class T>
List<T>& List<T>::operator = (List<T>& L) {
T value;
LinkNode<T>* destptr = first, * srcptr = L.first;
makeEmpty(); //先清空,后复制
while (srcptr->link != NULL)
{
value = srcptr->link->data;
destptr->link = new LinkNode<T>(value);
destptr = destptr->link;
srcptr = srcptr->link;
}
destptr->link = NULL;
return *this;
}
//单链表的插入算法 时间复杂度:Θ (i)
template <class T>
bool List<T>::Insert(int i, T x)
{ //将新元素 x 插入在链表中第 i 个结点之后
LinkNode<T>* current = Locate(i);
if (current == NULL) return false; //无插入位置
LinkNode<T>* newNode = new LinkNode<T>(x);
//创建新结点
if (newNode == NULL) {
cout << "创建失败" << endl;
return false;
}
newNode->link = current->link; //链入
current->link = newNode;
return true; //插入成功
}
//单链表的删除算法 时间复杂度:Θ (i)
template <class T>
bool List<T>::Remove(int i, T& x)
{ //删除链表第i个元素, 通过引用参数x返回元素值
LinkNode<T>* current = Locate(i - 1);
if (current == NULL || current->link == NULL)
return false; //删除不成功
LinkNode<T>* del = current->link;
current->link = del->link;
x = del->data;
delete del;
return true;
}
//单链表的逆置
template <class T>
void List<T>::reverse() {
if (first->link->link == NULL) return;
//双指针
LinkNode<T>* c1 = first->link;
LinkNode<T>* c2 = first->link->link;
int i = 1;
while (c2 != NULL) {
//保留下一位地址
LinkNode<T>* p1 = c2;
LinkNode<T>* p2 = c2->link;
c2->link = c1;//逆转指向
//迭代
c1 = p1;
c2 = p2;
i++;//计算结点个数
}
//逆置后,改变头尾指针
first->link = c1;
LinkNode<T>* last = Locate(i);
last->link = NULL;
}
//单链表的合并,合并后L链表需要指向空指针,避免与this链表共享空间导致重复析构
template <class T>
List<T>& List<T>::combine(const List<T>& L) {
LinkNode<T>* cur = first;
LinkNode<T>* cur1 = first->link;
LinkNode<T>* cur2 = L.first->link;
int len = Length() + L.Length();
if (cur1 == NULL && cur2 == NULL) return *this;
while (cur1 != NULL && cur2 != NULL) {
if (cur1->data <= cur2->data) {
cur->link = cur1;
cur = cur->link;
cur1 = cur1->link;
}
else {
cur->link = cur2;
cur = cur->link;
cur2 = cur2->link;
}
}
cur1 == NULL ? cur->link = cur2 : cur->link = cur1;
L.first->link = NULL;
reverse();
return *this;
}
//递归顺序输出到文件
template <class T>
void List<T>::foutput1(ofstream& out, LinkNode<T>* cur) {
if (cur) {
out << cur->data << " ";
cur = cur->link;
foutput1(out, cur);
}
else {
out << endl;
return;
}
}
//递归逆序输出到文件
template <class T>
void List<T>::foutput2(ofstream& out, LinkNode<T>* cur) {
if (cur) {
T temp = cur->data;
cur = cur->link;
foutput2(out, cur);
out << temp << " ";
}
else {
return;
}
}
int main() {
List<int> a, b, c;
//创建文件流对象
ifstream in1("a.txt", ios::in);
ifstream in2("b.txt", ios::in);
ifstream in3("c.txt", ios::in);
ofstream out("result.txt", ios::out);
ofstream out1("result1.txt", ios::out);
ofstream out2("result2.txt", ios::out);
//读入文件创建链表
a.input(in1);
//删除(1,3)范围外的文件
a.saveMinToMax(1, 3);
//将链表输出到文件
a.foutput(out);
return 0;
}
C++单链表的模板类实现(含文件输入输出)
于 2021-10-05 14:31:46 首次发布
本文档详细介绍了C++模板如何实现链表类List,包括链表的构造、搜索功能、链表长度计算、文件输入输出操作。核心展示了链表节点的定义、链表类的复制构造函数、链表清空、长度获取、元素搜索、数据访问与修改、插入与删除,以及链表的逆置和文件输出两种格式。
摘要由CSDN通过智能技术生成