c++ 用类模版实现链表(c++语言程序设计第四版示例代码)

本文通过C++的类模板来实现链表的数据结构,详细介绍了如何利用模板类进行节点定义、插入、删除等操作,是《C++语言程序设计》第四版中的示例代码解析。
摘要由CSDN通过智能技术生成
#include<iostream>
#include<cassert>
using namespace std;
template<class T>
class Node
{
private:
Node<T> * next;
public:
T data; //数据域

Node(const T & data, Node<T> * next = 0):data(data),next(next){} //构造函数

void InsertAfter(Node<T> *p){ //在本结点之后出入一个同类结点P
p->next = next; //P结点指针域指向当前结点的后继结点
next = p; //当前结点的指针域指向P
}

Node<T> *DeleteAfter(){ //删除本结点的后继结点,并返回其地址
Node<T>* tempp = next; //将欲删除的结点地址储存到tempp中
if (next == 0) //如果当前结点没有后继结点,则反回空指针
return 0;
next = tempp->next; //使当前结点的指针域指向tempp的后继结点
return tempp; //返回被删除的结点的地址
}

Node<T> *NextNode(){ return next; } //获取后继结点的地址

const Node<T>* NextNode()const{ return next; } //获取后继结点的地址

~Node(){}
};

template <class T>
class LinkedList {
private:
// 数据成员:
Node<T> *front, *rear; // 表头和表尾指针
Node<T> *prevPtr, *currPtr; // 记录表当前遍历位置的指针,由插入和删除操作更新
int size; // 表中的元素个数
int position; // 当前元素在表中的位置序号。由函数 Reset 使用

// 函数成员:

// 生成新结点,数据域为 item,指针域为 ptrNext

Node<T>* NewNode(const T &item, Node<T> *ptrNext = NULL){
Node<T> *newNode;

newNode = new Node<T>(item, ptrNext);

if (newNode == NULL) {
cerr << "Memory allocation failure!" << endl;
exit(1);
}

return newNode;
}

// 释放结点
void FreeNode(Node<T> *p){
delete p;
}

// 将链表 L 拷贝到当前表(假设当前表为空)。
// 被复制构造函数和“operator =”调用
void Copy(const LinkedList<T> &L){
if (L.size == 0)
return;

front = rear = NewNode(L.front->Data);

for (Node<T> *srcNode = L.front->NextNode();
srcNode != NULL;
srcNode = srcNode->NextNode())
{
Node<T> *newNode = NewNode(srcNode->Data);
rear->InsertAfter(newNode);
rear = newNode;
}

size = L.size;
Reset(position = L.CurrentPosition());
}


public:
//默认构造函数-空
LinkedList(void): front(NULL), rear(NULL), prevPtr(NULL), currPtr(NULL), size(0), position(0){}
LinkedList(const LinkedList<T> &L) : front(NULL), rear(NULL), prevPtr(NULL), currPtr(NULL), size(0), position(0){Copy(L);}//复制构造函数
~LinkedList(void){//析构函数
Clear();
}
LinkedList<T>& operator =(const LinkedList<T> &L){ // 重载赋值运算符
Clear();
Copy(L);

return *this;
}

int GetSize(void) const{ // 返回链表中元素个数
return size;
}
bool IsEmpty(void) const{ // 链表是否为空
return (size == 0);
}

/**
@brief 初始化游标的位置
@param pos 从零计起的位置编号
@note pos 无限制
当 pos 在 0 和 size 之间时,prevPtr 和 currPtr 正常指示;
当 pos 为 0 时,prevPtr = NULL, currPtr = front;
当 pos 为 size 时,prevPtr = rear, currPtr = NULL;
当 pos 取其他值时,prevPtr = currPtr = NULL。
*/
void Reset(int pos = 0){ // 初始化游标的位置
if (0 <= pos && pos <= size) {
position = 0;
prevPtr = NULL;
currPtr = front;
// 游标回到头结点,再逐步前移
while (pos--)
Next();
}
else {
position = pos;
prevPtr = NULL;
currPtr = NULL;
}
}
void Next(void){ // 使游标移动到下一个结点
position++;
prevPtr = currPtr;

if (currPtr != NULL)
currPtr = currPtr->NextNode();
}
/**
@brief 游标是否到了链尾
@return 游标是否到了链尾
游标“到了链尾”意即游标“超出了链表”,
当游标所示的当前结点不存在时即判断到了链尾。
*/
bool EndOfList(void) const{
return (currPtr == NULL);
}

/**
@brief 返回游标当前的位置
@return 从零计起的位置编号
@note 游标可以在链表之外
*/
int CurrentPosition(void) const{
return position;
}

void InsertFront(const T &item){ // 在表头插入结点
front = NewNode(item, front);

if (IsEmpty())
rear = front;

size++;
Reset(++position);
}

void InsertRear(const T &item){ // 在表尾插入结点
Node<T> *newNode = NewNode(item);

if (IsEmpty()) {
front = rear = newNode;
}
else {
rear->InsertAfter(newNode);
rear = newNode;
}

size++;
Reset(position);
}


/**
@brief 在当前结点之前插入结点
@param item 新结点的数据域
@note 只考虑当前位置的结点存在的情况
*/

void InsertBefore(const T &item){
if (currPtr != NULL) {
Node<T> *newNode = GetNode(item, currPtr);

if (prevPtr != NULL)
prevPtr->InsertAfter(newNode);
else
front = prevPtr = newNode;

size++;
Reset(++position);
}
}


/**
@brief 在当前结点之后插入结点
@param item 新结点的数据域
@note 只考虑当前位置的结点存在的情况
*/
void InsertAfter(const T &item){
if (currPtr != NULL) {
Node<T> *newNode = NewNode(item, currPtr->NextNode());
currPtr->InsertAfter(newNode);

if (rear == currPtr)
rear = newNode;

size++;
}
}

T DeleteFront(void){ // 删除头结点
if (IsEmpty()) {
cerr << "List is empty, delete error." << endl;
exit(1);
}

Node<T> *delNode = front;
front = front->NextNode();

if (--size == 0)
rear = NULL;

Reset(--position);

T item = delNode->data;
FreeNode(delNode);

return item;
}

void DeleteCurrent(void){ // 删除当前结点
if (currPtr != NULL) {
if (front == currPtr)
front = currPtr->NextNode();

if (rear == currPtr)
rear = prevPtr;

if (prevPtr != NULL)
prevPtr->DeleteAfter();

FreeNode(currPtr);
size--;
Reset(position);
}
}

T& Data(void){ // 返回对当前结点成员数据的引用
if (currPtr == NULL) {
cerr << "Current node is invalid." << endl;
exit(1);
}

return currPtr->data;
}

const T& Data(void) const{ // 返回对当前结点成员数据的常引用
if (currPtr == NULL) {
cerr << "Current node is invalid." << endl;
exit(1);
}

return currPtr->data;
}

// 清空链表:释放所有结点的内存空间。被析构函数和“operator =”调用
void Clear(void){
while (!IsEmpty())
DeleteFront();
}
};


int main(){
LinkedList<int> linklist;
for (int i = 0; i < 10; i++){
int x;
cin >> x;
linklist.InsertFront(x);
}

linklist.Reset(0);
while (!linklist.EndOfList()){
cout << linklist.Data() << endl;
linklist.Next();
}
cout << endl;
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值