单向链表的节点类模板和链表类模板

1.定义结点类模板:CNode.h


插入操作算法


删除操作算法


#ifndef CNODE_INCLUDE_H
#define CNODE_INCLUDE_H
//结点类模板的定义
template <class T> class CNode{
private:
	CNode<T> *next;  //指向后继结点的指针(指针域)
public:
	T data;  //数据域
	CNode(const T& data, CNode<T> *next = 0);  //构造函数
	void InsertAfter(CNode<T> *p);  //在本节点之后插入一个同类结点p
	CNode<T>* DeleteAfter();  //删除本节点的后继结点,并返回其地址
	CNode<T>* NextNode();  //获取后继结点的地址
	const CNode<T> *NextNode()const;  //获取后继结点的地址(常函数)
};
/*构造函数*/
template <class T> CNode<T>::CNode(const T& data, CNode<T> *next = 0) :data(data), next(next){}
/*返回后继结点的指针*/
template <class T> CNode<T>* CNode<T>::NextNode()
{
	return next;
}

/*在当前结点之后插入一个结点p*/
template <class T> void CNode<T>::InsertAfter(CNode<T> *p)
{
	p->next = next;  //p结点指针域指向当前节点的后继结点
	next = p;  //当前节点的指针域指向p
}
/*删除当前结点的后继结点,并返回其地址*/
template <class T> CNode<T>* CNode<T>::DeleteAfter()
{
	CNode<T> *tempPtr = next;  //将欲删除的节点地址存储到tempPtr
	if (next == 0)  //如果当前节点没有后继结点,则返回空指针
		return 0;
	next = tempPtr->next;  //使当前节点的指针域指向tempPtr的后继结点
	return tempPtr;
}
#endif

2.链表类模板的定义:

#ifndef LINKEDLIST_INCLUDE_H
#define LINKEDLIST_INCLUDE_H
#include "CNode.h"
//链表类模板
template <class T> class LinkedList{
private:
	//私有数据成员
	CNode<T> *front, *rear;  //表头和表尾指针
	CNode<T> *prevPtr, *currPtr;  //记录当前遍历位置的指针,由插入和删除操作更新
	int size;  //表中的元素个数
	int position;  //当前元素在表中的位置序号,由函数reset使用
	//私有函数成员,用于本类的内部函数调用
	CNode<T>* NewNode(const T& item, CNode<T>* ptrNext = NULL);  //生成新节点,数据域为item,指针域为ptrNext
	void FreeNode(CNode<T>* p);  //释放节点
	void Copy(const LinkedList<T>& L);  //将链表L拷贝到当前表(假设当前表为空),被拷贝构造函数,operator=调用

public:
	//共有成员函数
	LinkedList();  //构造函数
	LinkedList(const LinkedList<T> &L);  //拷贝构造函数
	~LinkedList();  //析构函数
	LinkedList<T>& operator=(const LinkedList<T>& L);  //重载赋值运算符
	int GetSize()const;  //返回链表中的元素个数
	bool IsEmpty()const;  //链表是否为空
	void ReSet(int pos = 0);  //初始化游标的位置
	void Next();  //使游标移动到下一个节点
	bool EndOfList()const;  //游标是否到了链尾
	int CurrentPosition()const;  //返回游标当前的位置
	void InsertFront(const T& item);  //在表头插入结点
	void InsertRear(const T& item);  //在表尾插入结点
	void InsertAt(const T& item);  //在当前结点之前插入结点
	void InsertAfter(const T& item);  //在当前结点之后插入结点

	T DeleteFront();  //删除头结点
	void DeleteCurrent();  //删除当前结点
	T& data();  //返回当前节点成员数据的引用
	const T& data()const;  //返回当前节点的数据应用(常函数)
	void Clear();  //清空链表:释放所有结点的内存空间。被析构函数调用
};
/*生成新节点*/
template <class T> CNode<T>* LinkedList<T>::NewNode(const T& item, CNode<T>* ptrNext)
{
	CNode<T>* p;
	p = new CNode<T>(item, ptrNext);
	if (p == NULL)
	{
		cout << "Memory allocation failure!" << endl;
		exit(1);
	}
	return p;
}
/*释放节点*/
template <class T> void LinkedList<T>::FreeNode(CNode<T>* p)
{
	delete p;
}
/*复制链表*/
template <class T> void LinkedList<T>::Copy(const LinkedList<T>& L)
{
	CNode<T> *p = L.front;  //p用来遍历L
	int pos;
	while (p != NULL)  //将L中的每一个元素插入到当前连接表最后
	{
		InsertRear(p->data);
		p = p->NextNode();
	}
	if (position == -1) //如果链表为空,则返回
		return;
	//在新链表中重新设置prevPtr和currptr
	prevPtr = NULL;
	currPtr = front;
	for (pos = 0; pos != position; pos++)
	{
		prevPtr = currPtr;
		currPtr = currPtr->NextNode();
	}
}
/*构造函数,构造新链表,size为0,positon为-1*/
template <class T> LinkedList<T>::LinkedList() :front(NULL), rear(NULL), prevPtr(NULL), currPtr(NULL), size(0), position(-1){}
/*拷贝构造函数*/
template <class T>LinkedList<T>::LinkedList(const LinkedList<T>& L)
{
	front = rear = NULL;
	prevPtr = currPtr = NULL;
	size = 0;
	position = -1;
	Copy(L);
}
/*析构函数*/
template <class T> LinkedList<T>::~LinkedList()
{
	Clear();
}
/*重载赋值运算符*/
template <class T> LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& L)
{
	if (this == &L)  //不能将链表赋值给它自身
		return *this;
	Clear();
	Copy(L);
	return *this;
}
/*获取链表的大小*/
template <class T> int LinkedList<T>::GetSize()const
{
	return size;
}
/*判断链表是否为空*/
template <class T> bool LinkedList<T>::IsEmpty()const
{
	return size == 0;
}
/*将链表当前位置设置为pos*/
template <class T>void LinkedList<T>::ReSet(int pos)
{
	int startPos;
	if (front == NULL) //如果链表为空
		return;
	if (pos<0 || pos>size - 1)  //如果指定位置不合法,返回
	{
		cerr << "ReSet:Invalid list position: " << pos << endl;
		return;
	}
	//设置与链表有关的成员
	if (pos == 0)  //如果pos为0,将指针重新设置到表头
	{
		prevPtr = NULL;
		currPtr = front;
		position = 0;
	}
	else  //否则重新设置currPtr,prevPtr,position
	{
		currPtr = front->NextNode();
		prevPtr = front;
		startPos = 1;
		for (position = startPos; position!=pos; position++)
		{
			prevPtr = currPtr;
			currPtr = currPtr->NextNode();
		}
	}
}
/*将prevPtr和currPtr先前移动一个结点*/
template <class T>void LinkedList<T>::Next()
{
	if (currPtr != NULL)
	{
		prevPtr = currPtr;
		currPtr = currPtr->NextNode();
		position++;
	}
}
/*判断是否已到达链表尾*/
template <class T> bool LinkedList<T>::EndOfList()const
{
	return currPtr == NULL;
}
/*返回当前节点的位置*/
template <class T> int LinkedList<T>::CurrentPosition()const
{
	return position;
}
/*将item插入在表头*/
template <class T> void LinkedList<T>::InsertFront(const T& item)
{
	if (front != NULL)  //如果链表不为空,则调用ReSet()
		ReSet();
	InsertAt(item);  //在表头插入
}
/*在表尾插入结点*/
template <class T> void LinkedList<T>::InsertRear(const T& item)
{
	CNode<T> *nNode;
	prevPtr = rear;
	nNode = NewNode(item);  //创建新节点
	if (rear == NULL)  //如果表为空,则插入在表头
		front = rear = nNode;
	else
	{
		rear->InsertAfter(nNode);
		rear = nNode;
	}
	currPtr = rear;
	position = size;
	size++;
}
/*将item插入在当前位置*/
template <class T> void LinkedList<T>::InsertAt(const T& item)
{
	CNode<T> *nNode;
	if (prevPtr == NULL)  //插入在链表头,包括将结点插入到空表中
	{
		nNode = NewNode(item, front);
		front = nNode;
	}
	else  //插入到链表之中,将结点置于prevPtr之后
	{
		nNode = NewNode(item);
		prevPtr->InsertAfter(nNode);
	}
	if (prevPtr == rear)//正在向空表中插入,或者是插入到非空表的表尾
	{
		rear = nNode;  //更新rear
		position = size;   //更新position
	}
	currPtr = nNode;  //更新currPtr
	size++;  //更新szie
}
/*将item插入到当前位置之后*/
template <class T>void LinkedList<T>::InsertAfter(const T& item)
{
	CNode<T> *p;
	p = NewNode(item);
	if (front == NULL)  //向空链表中插入
	{
		front = currPtr = rear = p;
		position = 0;
	}
	else  //插入到
	{
		if (currPtr == NULL)
			currPtr = prevPtr;
		currPtr->InsertAfter(p);
		if (currPtr == rear)
		{
			rear = p;
			position = szie;
		}
		else
			position++;
		prevPtr = currPtr;
		currPtr = p;
	}
	size++;  //更新链表长度
}
/*删除表头结点*/
template <class T> T LinkedList<T>::DeleteFront()
{
	T item;
	ReSet();
	if (front == NULL)
	{
		cerr << "Invalid deletion!" << endl;
		exit(1);
	}
	item = currPtr->data;
	DeleteCurrent();
	return item;
}
/*删除链表当前位置的结点*/
template <class T> void LinkedList<T>::DeleteCurrent()
{
	CNode<T> *p;
	if (currPtr == NULL)//如果链表为空或者到达表尾
	{
		cerr << "Invalid deletion!" << endl;
		exit(1);
	}
	if (prevPtr == NULL) //删除操作发生在表头或者表中
	{
		p = front;  //保存头结点地址
		front = front->NextNode();  //将其从链表分离
	}
	else  //分离prevPtr之后的一个内部结点,保存其地址
	{
		p = prevPtr->DeleteAfter();
	}
	if (p == rear)  //如果尾节点被删除
	{
		rear = prevPtr;  //新的表尾是prevPtr
		position--;  //position回退一步
	}
	currPtr = p->NextNode();  //使currPtr越过被删除的结点
	FreeNode(p);  //释放节点,并使链表长度减-
	size--;
}
//返回一个当前节点的数值引用
template <class T>T& LinkedList<T>::data()
{
	if (size == 0 || currPtr == NULL) //如果链表为空,或者到达链表尾
	{
		cerr << "Data:invalid reference!" << endl;
		exit(1);
	}
	return currPtr->data;
}
/*清空链表*/
template <class T> void LinkedList<T>::Clear()
{
	CNode<T> *currPosition, *nextPosition;
	currPosition = front;
	while (currPosition != NULL)
	{
		nextPosition = currPosition->NextNode(); //取得下一个结点的地址
		FreeNode(currPosition);//删除当前节点
		currPosition = nextPosition;  //当前指针移到下一个结点
	}
	front = rear = NULL;
	prevPtr = currPtr = NULL;
	size = 0;
	position = -1;
}
#endif

3.测试代码:

#include <iostream>
#include "LinkedList.h"

using namespace std;

int main() 
{
	LinkedList<int> list;
	for (int i = 0; i < 10; i++)
	{
		int item;
		cin >> item;
		list.InsertFront(item);  //在表头插入
	}
	cout << "list:";
	list.ReSet();
	while (!list.EndOfList())
	{
		cout << list.data() << " ";
		list.Next(); //指针下移
	}
	cout << endl;
	int key;  //词条,用于删除
	cout << "Please enter some integer needed to be deleted:";
	cin >> key;
	list.ReSet();
	while (!list.EndOfList())
	{
		if (list.data() == key)
			list.DeleteCurrent();
		list.Next(); //指针下移
	}
	cout << "list:";
	list.ReSet();
	while (!list.EndOfList())
	{
		cout << list.data() << " ";
		list.Next();
	}
	cout << endl;
	return 0;
}

测试结果:



来自清华大学MOOC课件


面向对象程序设计课程作业 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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值