模板链表类的扩展(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++函数模板与类模板的理解.具体内容如下: 泛型编程( ...
随机推荐
- JS神奇的或0(|0)
按照常识,位运算x|0,要么等于x,要么等于0 那么在JS的世界你的认知就要被颠覆了 下面请看 不带或0运算: (window.crypto.getRandomValues(new Uint32Arr ...
- Git配置环境变量
由于学习需要装了git,使用终端查看版本号时 提示 'git' 不是内部或外部命令,也不是可运行的程序 或批处理文件. 原因 因为没有配置Git环境变量 解决方法:配置环境变量 开始菜单=>设置 ...
- TCP/UDP 协议和 HTTP/FTP/SMTP 协议之间的区别
前言 我们经常会听到HTTP协议.TCP/IP协议.UDP协议.Socket.Socket长连接.Socket连接池等字眼,然而它们之间的关系.区别及原理并不是所有人都能理解清楚. 计算机网络体系结构 ...
- yb课堂 谷歌开源缓存框架Guava cache,封装API 《二十》
Guava cache github地址:点我直达 全内存的本地缓存实现 高性能且功能丰富 线程安全,操作简单 添加依赖 <dependency> <groupId>com.g ...
- Spring5.X的注解配置项目
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...
- C#-WPF初学
1.新建一个WPF的应用: 2.拖拽控件并布局好: [小技巧]选中控件,点击"回形针"即可让该控件跟随窗口自动调整大小: 3.编写代码: 主程序代码如下: namespace Wp ...
- 2. CMake 的简单使用
2. CMake 的简单使用 我们创建一个工程目录,在里面定义一些简单的加减乘除运算,然后定义一个 main.cpp 的文件: 结构如下: tree /f .\ D:\SOURCE\CMAKE_PRO ...
- 怒肝半月!Python 学习路线+资源大汇总
Python 学习路线 by 鱼皮. 原创不易,请勿抄袭,违者必究! 大家好,我是鱼皮,肝了十天左右的 Python 学习路线终于来了~ 和之前一样,在看路线前,建议大家先通过以下视频了解几个问题: ...
- NodeJS中Buffer与字符串相互转换时一个值得注意的问题
什么问题 如果一个Buffer的 toString() 结果为乱码或含有乱码,那么用此字符串以 Buffer.from()方法构造出来的Buffer将与原来的Buffer不相同. 这一点其实很好理解, ...
- Python 插件式程序设计与开发实践总结
插件式程序设计与开发实践总结 By:授客 QQ:1033553122 开发环境 win 10 python 3.6.5 代码结构