SglLinkedList.h文件
#pragma once
/*
*Copyright© 中国地质大学(武汉) 信息工程学院
*All right reserved.
*
*文件名称:SysLog.h
*摘 要:实现系统登陆功能
*
*当前版本:1.0
*作 者:邵玉胜
*完成日期:2018-03-09
*/
#include<iostream>
using namespace std;
//结点模板类定义
template<class T>
struct LinkedNode
{
T _data; //存放数据域
LinkedNode* _next; //存放指针域,指向下一结点
LinkedNode(LinkedNode<T>* ptr = nullptr) { //仅初始化指针成员的构造函数
_next = ptr;
}
//初始化指针域与数据域的构造函数
LinkedNode(const T& data, LinkedNode<T>* ptr = nullptr) {
_data = data;
_next = ptr;
}
};
//单链表模板类定义
template<class T>
class SglLinkedList
{
private:
LinkedNode<T>* _pFirst; //指向头结点的指针
int _iCurrent; //保存结点数
LinkedNode<T>* _pRear; //指向尾结点的指针
public:
SglLinkedList(); //构造函数
void init(SglLinkedList<T>& listPar); //初始化函数
SglLinkedList(SglLinkedList<T>& listPar); //复制构造函数
//赋值运算符重载
SglLinkedList<T>& operator = (SglLinkedList<T> listPar);
~SglLinkedList(); //析构函数
//输入输出函数
void input(T endTag); //输入函数
void output(); //输出函数
//追加与插入函数
void append(const T data); //追加函数
bool insert(int pos, const T data); //插入函数,pos从1开始
//删除与置空函数
bool remove(int pos, T& data); //删除第pos个位置的数据并用data保存起来
void makeEmpty(); //将整个链表置空
//判断链表是否为空的函数
bool isEmpty()const { return (_iCurrent == 0) ? true:false; } //判断链表空否
////取特定位置数据的函数
bool getItem(const int pos, T& data)const; //取出pos个位置的数据并用data保存起来
//取头结点
LinkedNode<T>* getHead(); //获取头结点地址
LinkedNode<T>* getRear(); //获取尾结点地址
LinkedNode<T>* search(const T data)const; //搜索含数据x的元素
LinkedNode<T>* locate(const int pos)const; //取出第pos个元素的位置,pos从1开始
void sort(bool asc = true); //排序函数
int getLengh()const { return _iCurrent; }; //获取表的长度
};
template < class T >
SglLinkedList<T>::SglLinkedList()
{
_pRear = _pFirst = new LinkedNode<T>(); //创建头结点
if (_pFirst == nullptr) { //如果内存分配失败
cerr << "初始化时内存分配错误!" << endl;
exit(-1);
}
_iCurrent = 0; //还未包含结点
}
//获取头指针的函数
template<class T>
LinkedNode<T>* SglLinkedList<T>::getHead() {
return _pFirst;
}
//获取尾结点的地址
template<class T>
LinkedNode<T>* SglLinkedList<T>::getRear() {
return _pRear;
}
//初始化函数
template<class T>
void SglLinkedList<T>::init(SglLinkedList<T>& listPar) {
this->_iCurrent = listPar._iCurrent;
//临时变量,用于暂存结点值
T tempValue;
LinkedNode<T>* srcPtr = listPar.getHead(); //原参数变量中的头指针
LinkedNode<T>* destPtr = _pFirst = new LinkedNode<T>(); //本对象的头指针
while (srcPtr->_next != nullptr) { //当原参数的遍历还未达到末尾时
tempValue = srcPtr->_next->_data; //暂存从参数链表中的结点值
destPtr->_next = new LinkedNode<T>(tempValue); //开辟内存分配给结点
if (destPtr->_next == nullptr) { //内存分配错误
cerr << "内存分配错误!" << endl;
exit(-1);
}
destPtr = destPtr->_next; //循环:将destPtr的下一结点赋值给destPtr
srcPtr = srcPtr->_next; //循环:将destPtr的下一结点赋值给destPtr
}
//这一个应该可以省略
//destPtr = nullptr; //尾结点的指针指向空
}
//复制构造函数
template<class T>
SglLinkedList<T>::SglLinkedList(SglLinkedList<T>& listPar) {
init(listPar);
}
//赋值运算符重载
template<class T>
SglLinkedList<T>& SglLinkedList<T>::operator = (SglLinkedList<T> listPar) {
init(listPar);
}
//清空链表的函数
template<class T>
void SglLinkedList<T>::makeEmpty() {
LinkedNode<T>* destPtr = _pFirst->_next; //不能是LinkedNode<T>* destPtr = _pFirst,
//因为如果这样的话,循环之后之后一个元素的_next就是指向空的
//会导致这个元素删除不了
while (destPtr != nullptr) {
/*delete _pFirst->_next; //这种写法是错误的,不能够先删除
_pFirst = _pFirst->_next;*/
LinkedNode<T>* tempDel = destPtr; //临时指向
destPtr = destPtr->_next; //将_pFirst指向_pFirst->_next,用于循环
delete tempDel; //删除tempDel所指向的内存
}
_pFirst->_next = nullptr; //首结点地址为空
_pRear = _pFirst; //尾结点地址设为空
//下面这样写是不行的,因为delete之后,该结点中的_next成员已经不存在,就没有办法
//在下一个循环继续指向
/*LinkedNode<T>* destPtr = _pFirst;
while (destPtr->_next != nullptr) {
LinkedNode<T>* tempDel = destPtr->_next;
destPtr = destPtr->_next;
delete tempDel;
}
_pFirst->_next = nullptr;*/
_iCurrent = 0;
}
template<class T>
SglLinkedList<T>::~SglLinkedList()
{
//直接调用makeEmpty,详情查看makeEmpty()函数
makeEmpty();
}
//输入函数
//此处的输入不设定输入个数,以endTag作为结束标志
//后插法
template<class T>
void SglLinkedList<T>::input(T endTag) {
T tempValue;
LinkedNode<T>* destPtr = _pFirst; //不可写为LinkedNode<T>* destPtr = _pFirst->_next;
//因为_pFirst->next为null,这样赋值,
//即使destPtr开辟了空间,_pFirst->next仍为null
cout << "请开始输入结点元素,并以参数作为结点标志:" << endl;
while (cin >> tempValue) { //循环输入
if (tempValue == endTag) //如果遇到结束符,结束输入
break;
destPtr->_next = new LinkedNode<T>(tempValue); //将输入的值建立结点
if (destPtr == nullptr) { //分配内存失败
cerr << "内存分配错误!" << endl;
exit(-1);
}
_iCurrent++; //建立一个结点,结点数加一
_pRear = destPtr->_next;
destPtr = destPtr->_next; //开始指向下一结点,循环
}
//这个应该可以省略的
//destPtr = nullptr; //将最后一个destPtr指向空,结束输入
}
//输出函数
template<class T>
void SglLinkedList<T>::output() {
LinkedNode<T>* destPtr = _pFirst->_next; //建立一个指针指向头结点
if (isEmpty()) {
cout << "链表为空,不能输出!" << endl;
return;
}
while (destPtr != nullptr) { //当未达到尾结点
cout << destPtr->_data << " "; //输出结点数据
destPtr = destPtr->_next;
}
cout << endl;
return;
}
//追加函数
template<class T>
void SglLinkedList<T>::append(const T data) { //在末尾插入一个结点
_pRear->_next = new LinkedNode<T>(data); //为心结点申请内存
if (_pRear->_next == nullptr) { //如果内存分配失败
cerr << "内存分配错误!" << endl;
exit(-1);
}
_iCurrent++; //结点数加一
_pRear = _pRear->_next; //尾巴结点指针指向新结点
}
//插入函数,pos从1开始
template<class T>
bool SglLinkedList<T>::insert(int pos, const T data) {
if (pos < 1 || pos > _iCurrent) { //插入位置错误
cout << "插入的位置有误,只能插入在1~"<<_iCurrent<<"位置!" << endl;
return false;
}
//遍历到插入的位置
LinkedNode<T>* destPtr = _pFirst;
for (int i = 0; i < pos - 1; i++) {
destPtr = destPtr->_next;
}
//为插入位置的结点分配内存
LinkedNode<T>* insPtr = new LinkedNode<T>(data);
if (insPtr == nullptr) {
cerr << "内存分配错误!" << endl;
exit(-1);
}
insPtr->_next = destPtr->_next; //将待插入的结点的指针指向遍历最后的下一结点
destPtr->_next = insPtr; //遍历最后的下一结点的指针让将待插入结点的位置
_iCurrent++; //结点数加一,尾指针不变
return true;
}
//删除第pos个位置的数据并用data保存起来
//pos从1开始
template<class T>
bool SglLinkedList<T>::remove(int pos, T& data){
if (pos < 1 || pos > _iCurrent) { //插入位置错误
cout << "删除的位置有误,只能在1~" << _iCurrent << "位置删除!" << endl;
return false;
}
//遍历到删除的位置
LinkedNode<T>* destPtr = _pFirst;
for (int i = 0; i < pos - 1; i++) {
destPtr = destPtr->_next;
}
//如果删除的是最后一个元素,那么尾指针要变动
if (pos == _iCurrent) {
_pRear = destPtr;
}
LinkedNode<T>* delPtr = destPtr->_next;
data = delPtr->_data; //将删除的结点值保存起来
destPtr->_next = delPtr->_next; //将遍历到最后结点的指针指向被删除元素指向的结点
delete delPtr; //释放被删除的内存
_iCurrent--; //删除成功后,节点数减1
return true;
}
//取出pos个位置的数据并用data保存起来
template<class T>
bool SglLinkedList<T>::getItem(const int pos, T& data) const{
if (pos < 1 || pos > _iCurrent) { //插入位置错误
cout << "获取的位置有误,只能获取在1~" << _iCurrent << "位置的数据!" << endl;
return false;
}
//遍历到提取的位置
LinkedNode<T>* destPtr = _pFirst;
for (int i = 0; i < pos; i++) {
destPtr = destPtr->_next;
}
data = destPtr->_data; //将提取的结点值保存起来
return true;
}
//搜索含数据x的元素
//返回第一个含数据x的结点的地址
template<class T>
LinkedNode<T>* SglLinkedList<T>::search(const T data) const{
LinkedNode<T>* destPtr = _pFirst->_next; //建立一个新的指针指向首结点
while (destPtr != nullptr && destPtr->_data != data) { //当没有循环到末尾并且未找到数据之前一直循环
destPtr = destPtr->_next; //指向下一结点
}
//当达到末尾是指向的是空指针,否则指向的是含数据x的结点的地址
return destPtr;
}
//取出第pos个元素的位置,pos从1开始
template<class T>
LinkedNode<T>* SglLinkedList<T>::locate(const int pos) const{
if (pos < 1 || pos > _iCurrent) { //插入位置错误
cout << "获取的位置有误,只能获取在1~" << _iCurrent << "的位置的地址!" << endl;
return nullptr;
}
//遍历到删除的位置
LinkedNode<T>* destPtr = _pFirst;
for (int i = 0; i < pos; i++) {
destPtr = destPtr->_next;
}
return destPtr;
}
//排序函数
//默认为升序
template<class T>
void SglLinkedList<T>::sort(bool asc /*= true*/) {
if (isEmpty()) { //首先判断时候为空,为空不能排序
cout << "空链表,不能进行排序" << endl;
return;
}
for (LinkedNode<T>* idestPtr = _pFirst->_next; //第一层循环的初始条件是令一个指针指向首结点
idestPtr != _pRear; //判断条件是达到倒数第二个结点结束
idestPtr = idestPtr->_next) { //使当前指针指向下一结点
for (LinkedNode<T>* jdestPtr = idestPtr->_next; //第二层循环的初始条件使指向第一层循环初始条件的下一结点
jdestPtr != nullptr; //判断条件使是否达到尾指针
jdestPtr = jdestPtr->_next) { //使第二层循环的当前结点指向下一结点
if (asc == true) {
if (idestPtr->_data > jdestPtr->_data) {//如果使升序排序
T tempValue;
tempValue = idestPtr->_data;
idestPtr->_data = jdestPtr->_data;
jdestPtr->_data = tempValue;
}
}
else {
if (idestPtr->_data < jdestPtr->_data) {
T tempValue;
tempValue = idestPtr->_data;
idestPtr->_data = jdestPtr->_data;
jdestPtr->_data = tempValue;
}
}
}
}
return;
}
main.cpp文件(测试文件)
#include"SglLinkedList.h"
int main(){
SglLinkedList<int> test;
//测试输入函数
test.input(0);
//测试输出函数
test.output();
//测试输出长度函数
cout << test.getLengh() << endl;
//测试置空函数
/*test.makeEmpty();
test.output();
cout << test.getLengh() << endl;*/
//测试追加函数
test.append(99);
test.output();
cout << test.getLengh() << endl;
//测试插入函数
test.insert(3, 88);
test.output();
cout << test.getLengh() << endl;
//测试删除函数
int temp;
if (test.remove(3, temp)) {
cout << "删除成功,您删除的是:" << temp << endl;
cout << "删除之后的元素为:" << endl;
test.output();
}
else {
cout << "删除失败!" << endl;
}
//测试获取结点值的函数
if (test.getItem(3, temp)) {
cout << "获取成功,您获取的是:" << temp << endl;
}
else {
cout << "获取失败!" << endl;
}
//测试寻找函数
if (test.search(5) != nullptr) {
cout << test.search(5)->_data << endl;;
}
else {
cout << "未找到包含该数据的结点!" << endl;
}
//测试获取特定位置结点的位置的函数
if (test.locate(3) != nullptr) {
cout << "3的下一个结点值为:" << test.locate(3)->_next->_data << endl;
}
//测试排序函数
test.sort(false);
cout << "降序排序之后的链表为:" << endl;
test.output();
test.sort();
cout << "升序排序之后的链表为:" << endl;
test.output();
//测试赋值构造函数
cout << "赋值构造函数的测试:" << endl;
SglLinkedList<int>test2 = test;
test2.output();
if (test2.locate(3) != nullptr) {
cout << "3的下一个结点值为:" << test2.locate(3)->_next->_data << endl;
}
//测试赋值运算符的重载函数
SglLinkedList<int>test3 = test2;
cout << "赋值构造函数的测试:" << endl;
test3.output();
if (test3.locate(3) != nullptr) {
cout << "3的下一个结点值为:" << test3.locate(3)->_next->_data << endl;
}
return 0;
}
测试结果
