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课件