C++单链表的模板类实现(含文件输入输出)

本文档详细介绍了C++模板如何实现链表类List,包括链表的构造、搜索功能、链表长度计算、文件输入输出操作。核心展示了链表节点的定义、链表类的复制构造函数、链表清空、长度获取、元素搜索、数据访问与修改、插入与删除,以及链表的逆置和文件输出两种格式。
摘要由CSDN通过智能技术生成
#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;
}

面向对象程序设计课程作业 1. 请创建一个数据类型为T的链表类模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编写main函数,测试该类模板的正确性: 1) 用List模板定义一个List类型的模板类对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List类型的模板类对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List类型的模板类对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List类型的模板类对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值