首页 > 编程语言 >编程打卡:C++语言程序设计

编程打卡:C++语言程序设计

时间:2023-05-10 23:55:33浏览次数:34  
标签:Node 结点 const LinkedList 编程 C++ template currPtr 打卡

//Node.h
#ifndef NODE_H
#define NODE_H

//类模板的定义
template <class T>
class Node {
private:
	Node<T> *next;	//指向后继结点的指针
public:
	T data;	//数据域

	Node (const T &data, Node<T> *next = 0);    //构造函数
	void insertAfter(Node<T> *p);	//在本结点之后插入一个同类结点p
	Node<T> *deleteAfter();	//删除本结点的后继结点,并返回其地址
	Node<T> *nextNode();				 //获取后继结点的地址
	const Node<T> *nextNode() const;	 //获取后继结点的地址
};

//类的实现部分
//构造函数,初始化数据和指针成员
template <class T>
Node<T>::Node(const T& data, Node<T> *next/* = 0 */) : data(data), next(next) { }

//返回后继结点的指针
template <class T>
Node<T> *Node<T>::nextNode() {
	return next;
}

//返回后继结点的指针
template <class T>
const Node<T> *Node<T>::nextNode() const {
	return next;
}

//在当前结点之后插入一个结点p
template <class T>
void Node<T>::insertAfter(Node<T> *p) {
    p->next = next;	//p结点指针域指向当前结点的后继结点
    next = p;		//当前结点的指针域指向p
}

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

#endif //NODE_H
//LinkedList.h
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"

#include<iostream>
using namespace std;

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);

	//释放结点
	void freeNode(Node<T> *p);

	//将链表L 拷贝到当前表(假设当前表为空)。
	//被拷贝构造函数、operator = 调用
	void copy(const LinkedList<T>& L);

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;   //返回对当前结点成员数据的常引用

	//清空链表:释放所有结点的内存空间。被析构函数、operator= 调用
	void clear();
};

template <class T>
Node<T> *LinkedList<T>::newNode(const T& item, Node<T>* ptrNext)	//生成新结点
{
	Node<T> *p;
	p = new Node<T>(item, ptrNext);
	if (p == NULL)
	{
		cout << "Memory allocation failure!\n";
		exit(1);
	}
	return p;
}

template <class T>
void LinkedList<T>::freeNode(Node<T> *p) //释放结点
{
	delete p;
}

template <class T>
void LinkedList<T>::copy(const LinkedList<T>& L) //链表复制函数
{
	Node<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();
	}
}

template <class T>  //构造一个新链表,将有关指针设置为空,size为0,position为-1
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;
}

template <class T>
void LinkedList<T>::reset(int pos)	//将链表当前位置设置为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();
		}
	}
}

template <class T>
void LinkedList<T>::next()	//将prevPtr和currPtr向前移动一个结点
{
	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;
}

template <class T>
void LinkedList<T>::insertFront(const T& item)   // 将item插入在表头
{
	if (front != NULL)	// 如果链表不空则调用Reset
		reset();
	insertAt(item);	// 在表头插入
}


template <class T>
void LinkedList<T>::insertRear(const T& item)   // 在表尾插入结点
{
	Node<T> *nNode;
	prevPtr = rear;
	nNode = newNode(item);	// 创建新结点
	if (rear == NULL)	// 如果表空则插入在表头
		front = rear = nNode;
	else
	{
		rear->insertAfter(nNode);
		rear = nNode;
	}
	currPtr = rear;
	position = size;
	size++;
}


template <class T>
void LinkedList<T>::insertAt(const T& item)	// 将item插入在链表当前位置
{
	Node<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++;	//使size增值
}


template <class T>
void LinkedList<T>::insertAfter(const T& item)  // 将item 插入到链表当前位置之后
{
	Node<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 = size;
		}
		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()	// 删除链表当前位置的结点
{
	Node<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()	//清空链表
{
	Node<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  //LINKEDLIST_H

标签:Node,结点,const,LinkedList,编程,C++,template,currPtr,打卡
From: https://www.cnblogs.com/sugar-refinery/p/17389744.html

相关文章

  • 第十三天打卡
    以平面图形类Plane为基类公有派生三角形类Triangle,main(void)函数完成对其的测试。题目:#include<iostream>#include<cmath>usingnamespacestd;//点类PointclassPoint{private:doublex;doubley;public:Point(doublexv=0,doubleyv=0);/*构造函数*/......
  • 2023.5.10编程一小时打卡
    一、问题描述:给出下面的人员基类框架:classPerson{protected:stringname;intage;public:Person();Person(stringp_name,intp_age);voiddisplay(){cout<<name<<“:”<<age<<endl;}};建立一个派生类student,增加以下成员数据:in......
  • Linux网络编程(学习笔记)
    文中python代码来自老师的教学代码,感谢我的老师~~1.linux网络数据处理过程:网卡->协议栈->网络1)应用层输出数据socket层->协议层->接口层2)应用层接收数据内核层(接口层->协议层->插口层)->用户空间的用户应用2.socket是什么socket类似jdbc,是一种接口,每种操作系统有不同的实......
  • 5.10打卡
      三、程序流程图 四、代码实现#include<bits/stdc++.h>#defineN10usingnamespacestd;main(){inti,a[N]={-3,4,7,9,13,45,67,89,100,180},low=0,high=N-1,mid,k=-1,m;printf("aÊý×éÖеÄÊý¾ÝÈçÏÂ:\n");for(i=0;i<N;i++)p......
  • c++打卡训练
    自守数(半成品,指没写出来,双倍给明天)流程图:伪代码:源代码:#include<iostream>usingnamespacestd;intmain(){ longinti,m; intj,n,k,a=1; for(i=0;i<=100000;i++){ n=i; m=i*i; for(j=0;n=0;j++){ n/=10; for(k=j;k>=0;k--){ a=a+a*10; if(m%a==i){ printf......
  • 每日打卡-20.1
    一.问题描述编写程序提示用户输入一个班级中的学生人数n,再依次提示用户输入n个人在课程A中的考试成绩,然后计算出平均成绩,显示出来。请使用本书第9章中的数组类模板Array定义浮点型数组存储考试成绩。二.设计思路按照题目要求编写代码三.流程图四.伪代码 1五.代码......
  • 每日打卡-20.2
    一.问题描述初始化int类型数组datal[]={1,3,5,7,9,11,13,15,17,19,2,4,6,8,10,12,14,16,18,20},应用本章的直接插入排序函数模板进行排序。对此函数模板稍做修改,加入输出语句,在每插入一个待排序元素后显示整个数组,观察排序过程中数据的变化,加深对插入排序算法的理解。二.设计思路三.流程图四.......
  • 5-10打卡 练习
    typedefstructlist{ intdata; list*next;}list;list*initlist(){ list*a=newlist; a->data=0; a->next=NULL; returna;}voidpushback(list**h,intn){list*a=newlist;a->data=n;a->next=NULL;list*......
  • 每日打卡
    回文数问题描述:回文数指形如abcba类的数,求小于n<256的回文数问题分析:看千位权重与十位相同需要用循环写出个位t与十位i代码:#include<stdio.h> intmain() {            intm[16],n,i,t,count=0;            longunsigneda,k;      ......
  • 5月10日打卡
    例4-11题目描述:设计一个结构体存储学生的成绩信息,需要包括学号年级和成绩三项内容,学号的范围是0到99999999,年级分为freshman、sophomore、junior、、senior四种,成绩包括A、S、C、D四个等级。分析:1.学号包括27个二进制位有效信息,而年级、成绩各包括2个二进制位有效信息,采用......