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

 

posted @ 2022-12-11 11:06  初吻给了烟灬  阅读(48)  评论(0编辑  收藏  举报