以前写的链表都是比较简单的,插入节点是在头节点上,所以循环链表时都是从最后一个数据往前找的,给人的感觉是倒着的,

今天写一个在链表尾部插入数据

1。链表节点类的定义

/链表节点类
template <class T>
class QNode
{
public:
QNode()
{
pNext = nullptr;
pData = nullptr;
}
public:
QNode<T>* pNext;//指向下一个节点的指针
T* pData;    //指向数据域的指针
};

2.链表类的定义

//顺序链表
template <class T>
class QListEx
{
typedef BOOL(*PFINDBOOL)(T*,PVOID);
public:
QListEx();
~QListEx();
public:
void AddNode(T* pData); //添加数据到链表中
void ClearAll();   //清除所有节点和数据域内存
void ClearNode();  //清除节点内存(不清除数据域内存,有可能数据域被别的链表应用)
void DelAt(int nIndex); //删除指定索引位置的节点
void SetAt(int nIndex,T* pData); //设置指定索引的数据域数据
int GetCount()const;      //获得节点个数
T* GetAt(int nIndex)const;  //获得节点数据域指针
T* FindSing(PFINDBOOL pBol);  //根据外部查寻条件返回单个数据域指针指向的内存
int FindIndex(PFINDBOOL pBol, PVOID pObject = 0); //根据外部查寻条件返回数据在链表中的索引值
int DelFind(PFINDBOOL pBol);             //根据外部查寻条件删除数据,返回删除的个数
QListEx<T>* FindArray(PFINDBOOL pBol,LPVOID lpData); //根据外部查寻条件返回符合条件的数据集合
BOOL IsNull();
BOOL IsModfiy()const; //判断链表数据是否有修改状态
QNode<T>* GetHeadNode()const; //获得头节点指针
void ClearModfiy(); //清除修改标志 protected:
QNode<T>* m_pHead; //头指针
QNode<T>* m_pEnd; //尾指针
int m_nCount; //节点个数
BOOL m_bTemList; //是否是临时链表
BOOL m_bModfiy; //链表数据是否有修改
};

3.链表类方法的实现

3.1.链表构造函数

template<class T>
inline QListEx<T>::QListEx()
{
m_pEnd = nullptr;
m_pHead = nullptr;
m_nCount = 0;
m_bTemList = FALSE;
m_bModfiy = FALSE;
}

3.2 添加节点数据到链表中(AddNode)

//添加新的节点
//参数是数据域的内存地址,所以在外面要New一个数据域内存
template <class T>
inline void QListEx<T>::AddNode(T* pData)
{
QNode<T>* pNode = new QNode<T>;
pNode->pData = pData; if (m_pHead == nullptr)//如果头节点为NULL,新节点为头节点
{
m_pHead = pNode;
m_pEnd = m_pHead;
}
else  //如果头节点不为空,尾节点的下一个指向新节点,再把新节点设置为尾节点
{
m_pEnd->pNext = pNode;
m_pEnd = pNode;
} m_bModfiy = TRUE;  //链表中的数据有修改状态
m_nCount++;
}

3.3在链表中查找符合指定条件的数据

指定条件只能是在外部传进来的数据,所以就要定义一个函数指针类型

typedef BOOL(*PFINDBOOL)(T*,PVOID);//外部要给链表传递查询条件的函数指针类型

QListEx<T>* FindArray(PFINDBOOL pBol,LPVOID lpData); //根据外部查寻条件返回符合条件的多个数据的临时链表用后要删除

//返回的链表用完用ClearNode函数清除节点内存,最后用Delete删除链表所在的内存
//注意:不要用ClearAll清除,不然数据域的内存也会被删除
template<class T>
inline QListEx<T>* QListEx<T>::FindArray(PFINDBOOL pBol,LPVOID lpData)
{
QListEx<T>* pList = new QListEx<T>;
pList->m_bTemList = TRUE; QNode<T>* pCurr = m_pHead;
while (pCurr != nullptr)
{
if (pBol(pCurr->pData,lpData))
{
pList->AddNode(pCurr->pData);
} pCurr = pCurr->pNext;
} return pList;
}

在测试中应用:

1定义数据域结构类型

struct Student
{
int id;
TCHAR name[10];
TCHAR sex[2];
UINT age;
TCHAR tel[12];
Student()
{
id = 0;
memset(&name, 0, sizeof(name));
memset(&sex, 0, sizeof(sex));
age = 0;
memset(&tel, 0, sizeof(tel)); }
Student(int id, LPCTSTR name, LPCTSTR sex, UINT age, LPCTSTR tel)
{
this->id = id;
_tcscpy_s(this->name,name);
_tcscpy_s(this->sex, sex);
this->age = age;
_tcscpy_s(this->tel, tel);
}
};

2.定义链表

QListEx<Student>* m_pStuArray=new QListEx<Student>;

3.添加数据或是从文件中读取数据到链表中

下面的实例是从文件中读取数据到链表中

QFile file;
if (!file.OpenFile(FILENAME, QFile::modulRead))//没有找到要打开的文件就新建一个
{
file.CreateNewFile(FILENAME);
}
else
{
//从文件中读取数据循环添加到链表中
int nLeng = file.GetFileSize();
int readLeng = 0;
while (nLeng)
{
Student* pStu = new Student;
readLeng = file.ReadBinaryFile(pStu, sizeof(Student));
m_pStuArray->AddNode(pStu);
nLeng = nLeng - readLeng;
}
m_pStuArray->ClearModfiy();//清除链表的修改标志
}
file.CloseFile();

3.根据外部函数给定的查询条件返回符合条件的多个数据

void MyMainWnd::OnFindBtnClick()
{
QListEx<Student>* pList = m_pStuArray->FindArray(FindListData, this);
if (!pList->IsNull())
{
ShowStuArrayToListCtrl(&m_wndListCtrl, pList);
}
   pList.ClearNode();  //清除链表节点内存(不清除数据域内存)
delete pList;
pList = nullptr;
}

函数指针FindListData为全局函数

BOOL FindListData(Student* pStu, LPVOID lpData)
{
QWnd* pWnd = (QWnd*)lpData; //获得主窗口对象指针
BOOL bResult = FALSE; TCHAR editStr[10] = { 0 };
GetDlgItemText(pWnd->m_hWnd, IDC_FINDEDIT, editStr, 10);//获得编辑框中查询条件数据
TCHAR firChar = editStr[0]; QComboBox cmb = GetDlgItem(pWnd->m_hWnd, IDC_COMBO1); //获得组合框中分类数据
int nSel = cmb.GetCurSel();
UINT nVaule = 0;
//根据要查询的分类返回符合条件的数据
switch (nSel)
{
case 0://All
bResult = TRUE;
break; case 1://ID
#if 0 if (firChar == '>')
{
firChar = editStr[1];
if (firChar == '=')
{
nVaule = _ttoi(editStr + 2);
bResult = (pStu->id >= nVaule);
}
else
{
nVaule = _ttoi(editStr + 1);
bResult = (pStu->id > nVaule);
}
}
else if (firChar == '<')
{
firChar = editStr[1];
if (firChar == '=')
{
nVaule = _ttoi(editStr + 2);
bResult = (pStu->id <= nVaule);
}
else
{
nVaule = _ttoi(editStr + 1);
bResult = (pStu->id < nVaule);
}
}
else if (firChar == '=')
{
nVaule = _ttoi(editStr + 1);
bResult = (pStu->id == nVaule);
}
else
{
nVaule = _ttoi(editStr);
bResult = (pStu->id == nVaule);
}
#endif
bResult = CmpIntVaule(pStu->id, editStr);
break; case 2://Name
bResult = (_tcscmp(pStu->name, editStr) == 0);
break; case 3://Sex
bResult = (_tcscmp(pStu->sex, editStr) == 0);
break; case 4://Age
bResult = CmpIntVaule(pStu->age, editStr);
break; case 5://Tel
bResult = (_tcscmp(pStu->tel, editStr) == 0);
break; default:
break;
} return bResult;
}

模板链表类的扩展(QListEx<T>)的更多相关文章

  1. C++类功能扩展预留五招

    第一招虚函数 通过派生类来进行功能扩展是基本的面向对象的方式,这种方式大如下: class base { public: virtual ~base(){} virtual void fun() { ...

  2. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  3. C++复习:函数模板和类模板

    前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...

  4. C++解析(26):函数模板与类模板

    0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...

  5. 数据结构-单链表-类定义2-C++

    上一次的C++链表实现两个单链表的连接不太理想,此次听了一些视频课,自己补了个尾插法,很好的实现了两个链表的连接,当然了,我也是刚接触,可能是C++的一些语法还不太清楚,不过硬是花了一些时间尽量在数据 ...

  6. spring初始化源码浅析之关键类和扩展接口

    目录 1.关键接口和类 1.1.关键类之 DefaultListableBeanFactory 1.2.关键类之XmlBeanDefinitionReader 1.3.关键类之ClassPathXml ...

  7. 7 HandlerSet 处理程序链表类——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 my.oschina.net/oloroso Handler ...

  8. 20Spring_JdbcTemplatem模板工具类

    JdbcTemplate 是Spring提供简化Jdbc开发模板工具类.为了更好的了解整个JdbcTemplate配置数据库连接池的过程,这篇文章不采用配置文件的方式,而是采用最基本的代码 的方式来写 ...

  9. IOS基础之 (十二) 类的扩展

    对OC类的扩展总结如下,共有4个: 1.子类 subClass 作用:可以使用类的继承来增添父类的变量和方法. 写法:在.h文件中 @interface Student : Person 2.分类 C ...

  10. [Reprint] C++函数模板与类模板实例解析

    这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下   本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...

随机推荐

  1. mysql+redis点赞功能剖析

    最近在一个应用上需要用到点赞的功能,因为点赞的功能比较常用,很多人看到了大拇指就点了上去,如果单单采用mysql的方式的话可以会对数据库造成很大的压力. 我看了下网上一些博主的提供的解决方案,主要以m ...

  2. 高通android QMI机制

    高通android QMI机制 原文(有删改):https://blog.csdn.net/u012439416/category_7004974 概论 Qualcomm MSM Interface, ...

  3. Oracle常用统计

    测试, 这是测消息 1.按天 select to_char(t.STARTDATE+15/24, 'YYYY-MM-DD') as 天,sum(1) as 数量from HOLIDAY tgroup ...

  4. QuartzNet暂停恢复会执行多次的问题解决

    ' var config = new System.Collections.Specialized.NameValueCollection { { "quartz.jobStore.misf ...

  5. xlookup与vlookup的区别

    区别还是很大的,vlookup暂时扔不了.

  6. 转载 | [AcSaveAsType -cad版本代号对应数字 ] & [AutoCAD的DWG文件格式版本代号列表]

    1.  AcSaveAsType -cad版本代号对应数字 doc.SaveAs("D:\AutoCAD\1.dwg", 61) # 将当前文件另存为PyAutoCAD_SaveA ...

  7. 靶机练习: y0usef

    靶机: y0usef 准备工作 靶机地址: https://download.vulnhub.com/y0usef/y0usef.ova MD5 校验:28c5d869b003be94b2d8ab4b ...

  8. java面试一日一题:mysql执行delete数据真的被删除了吗

    问题:请讲下mysql执行了delete操作,数据真的被删除了吗 分析:这个问题考察对mysql底层存储的理解. 回答要点: 主要从以下几点去考虑, 1.肯定没有真正删除? 2.为什么这样设计? my ...

  9. 云计算:Docker-compose快速部署前后端项目

    | 更好的观看效果请前往,原文博客地址:https://www.zeker.top/posts/338829e1/ 介绍 Docker Compose 是官方编排的项目之一,负责快速的部署分布式应用. ...

  10. app专项测试:app弱网测试(测试工具)

    app专项测试:app弱网测试(测试工具) 除了常用的 fiddler,charles 可以模拟弱网,还有硬件工具弱网仪 HoloWAN也可以模拟弱网 使用弱网仪有以下优点:1.即插即用,无需调试和复 ...