模板链表类的扩展(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; }
签名:GreenLeaf1976