模板链表类的扩展(QListEx<T>)
以前写的链表都是比较简单的,插入节点是在头节点上,所以循环链表时都是从最后一个数据往前找的,给人的感觉是倒着的,
今天写一个在链表尾部插入数据
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>)的更多相关文章
- C++类功能扩展预留五招
第一招虚函数 通过派生类来进行功能扩展是基本的面向对象的方式,这种方式大如下: class base { public: virtual ~base(){} virtual void fun() { ...
- C++_进阶之函数模板_类模板
C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...
- C++复习:函数模板和类模板
前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...
- C++解析(26):函数模板与类模板
0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...
- 数据结构-单链表-类定义2-C++
上一次的C++链表实现两个单链表的连接不太理想,此次听了一些视频课,自己补了个尾插法,很好的实现了两个链表的连接,当然了,我也是刚接触,可能是C++的一些语法还不太清楚,不过硬是花了一些时间尽量在数据 ...
- spring初始化源码浅析之关键类和扩展接口
目录 1.关键接口和类 1.1.关键类之 DefaultListableBeanFactory 1.2.关键类之XmlBeanDefinitionReader 1.3.关键类之ClassPathXml ...
- 7 HandlerSet 处理程序链表类——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 my.oschina.net/oloroso Handler ...
- 20Spring_JdbcTemplatem模板工具类
JdbcTemplate 是Spring提供简化Jdbc开发模板工具类.为了更好的了解整个JdbcTemplate配置数据库连接池的过程,这篇文章不采用配置文件的方式,而是采用最基本的代码 的方式来写 ...
- IOS基础之 (十二) 类的扩展
对OC类的扩展总结如下,共有4个: 1.子类 subClass 作用:可以使用类的继承来增添父类的变量和方法. 写法:在.h文件中 @interface Student : Person 2.分类 C ...
- [Reprint] C++函数模板与类模板实例解析
这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下 本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...
随机推荐
- 使用 Spring 实现控制反转和依赖注入
使用 Spring 实现控制反转和依赖注入 概述 在本文中,我们将介绍IoC(控制反转)和DI(依赖注入)的概念,以及如何在Spring框架中实现它们. 什么是控制反转? 控制反转是软件工程中的一个原 ...
- 一文带你深入理解SpringMVC的执行原理
今天大致来看一下Spring MVC的执行流程是什么样的 执行流程:也就是一个请求是怎么到我们Controller的,返回值是怎么给客户端的 本文分析的问题: 文件上传的请求是怎么处理的 跨域是怎么处 ...
- podman+openresty+openssl,https双向认证demo测试
前言 暂不讨论https原理,单论配置的话: 1. https单项认证 server: server.crt + server.key client: server_ca.crt 2. https双向 ...
- python3 pip3 安装 xmlrpc 失败
python2 使用的是xmlrpclib库,到了 python3, 就直接使用 xmlrpc.client 和 xmlrpc.server了. 接下来,我使用 pip3 install xmlrpc ...
- 实现ASP.Net Core3.1运行在DockeDesktop下并用Nginx实现负载均衡
一.首先去https://docs.docker.com/get-docker/下载Windows版本的Docker Desktop并安装(需要win10专业版以上操作系统,并启用CPU虚拟化和安装H ...
- Django集成的密码找回功能
要实现忘记密码功能,您需要进行以下修改: 添加忘记密码链接到登录页面. 创建密码丢失修改页面. 创建密码修改页面. 编写相应的视图函数来处理密码丢失修改和密码修改逻辑. 编写发送验证信息到邮箱的逻辑. ...
- 数据仓库建模工具之一——Hive学习第四天
Hive的基本操作 1.3HIve的表操作(接着昨天的继续学习) 1.3.2 显示表 show tables; show tables like 'u*'; desc t_person; desc f ...
- Python 基于pymongo操作Mongodb学习总结
实践环境 Python 3.6.4 pymongo 4.1.1 pymongo-3.12.3-cp36-cp36m-win_amd64.whl 下载地址:https://pypi.org/simple ...
- Known框架实战演练——进销存基础数据
本文介绍如何实现进销存管理系统的基础数据模块,基础数据模块包括商品信息.供应商管理和客户管理3个菜单页面.供应商和客户字段相同,因此可共用一个页面组件类. 项目代码:JxcLite 开源地址: htt ...
- .NET跨平台UI框架Avalonia 11.1重磅发布
本篇为译文 原文地址 https://avaloniaui.net/blog/avalonia-11-1-a-quantum-leap-in-cross-platform-ui-development ...