MFC - 链表
链表是一种线性数据结构,其中每个元素都是一个单独的对象。 列表的每个元素(我们将其称为节点)包含两项——数据和对下一个节点的引用。 最后一个节点有一个对 null 的引用。
链表是一种由一组节点组成的数据结构,这些节点共同表示一个序列。 它是一种用结构来存储数据的方法,以便程序员可以在需要时自动创建一个新的位置来存储数据。 它的一些显着特征是 −
链接列表是包含项目的链接序列。
每个链接都包含到另一个链接的连接。
列表中的每个项目称为一个节点。
如果列表至少包含一个节点,则新节点将定位为列表中的最后一个元素。
如果列表只有一个节点,则该节点代表第一个和最后一个项目。
链接列表有两种类型 −
单链表
单链表是一种数据结构。 在单向链表中,链表中的每个节点都存储该节点的内容以及指向链表中下一个节点的指针或引用。

双向链表
双向链表是一种链接数据结构,由一组称为节点的顺序链接记录组成。 每个节点包含两个字段,它们是节点序列中前一个节点和下一个节点的引用。

CList类
MFC提供了一个类CList,它是一个模板链表实现,并且工作得很好。 CList 列表的行为类似于双向链接列表。 POSITION 类型的变量是列表的键。 您可以使用 POSITION 变量作为迭代器来顺序遍历列表,并作为书签来保存位置。
序号 | 名称和描述 |
---|---|
1 | AddHead 将一个元素(或另一个列表中的所有元素)添加到列表的头部(创建一个新的头部)。 |
2 | AddTail 将一个元素(或另一个列表中的所有元素)添加到列表的尾部(创建一个新的尾部)。 |
3 | Find 获取由指针值指定的元素的位置。 |
4 | FindIndex 获取由从零开始的索引指定的元素的位置。 |
5 | GetAt 获取给定位置的元素。 |
6 | GetCount 返回此列表中的元素数量。 |
7 | GetHead 返回列表的头元素(不能为空)。 |
8 | GetHeadPosition 返回列表头元素的位置。 |
9 | GetNext 获取下一个迭代元素。 |
10 | GetPrev 获取要迭代的前一个元素。 |
11 | GetSize 返回此列表中的元素数量。 |
12 | GetTail 返回列表的尾部元素(不能为空)。 |
13 | GetTailPosition 返回列表尾部元素的位置。 |
14 | InsertAfter 在给定位置之后插入新元素。 |
15 | InsertAfter 在给定位置之前插入新元素。 |
16 | IsEmpty 测试空列表条件(无元素)。 |
17 | RemoveAll 从此列表中删除所有元素。 |
18 | RemoveAt 从此列表中删除由位置指定的元素。 |
19 | RemoveHead 从列表头部删除元素。 |
20 | RemoveTail 从列表尾部删除元素。 |
21 | SetAt 将元素设置在给定位置。 |
以下是对CList对象的不同操作 −
创建CList对象
要创建 CList 值或对象的集合,必须首先确定集合值的类型。 您可以使用现有的基本数据类型之一,例如 int、CString、double 等,如下面的代码所示。
CList<double, double>m_list;
添加项目
要添加项目,您可以使用 CList::AddTail() 函数。 它在列表末尾添加一个项目。 要在列表的开头添加元素,可以使用 CList::AddHead() 函数。 在 OnInitDialog() CList 中,创建对象并添加四个值,如以下代码所示。
CList<double, double>m_list; //Add items to the list m_list.AddTail(100.75); m_list.AddTail(85.26); m_list.AddTail(95.78); m_list.AddTail(90.1);
检索项目
POSITION 类型的变量是列表的键。 您可以使用 POSITION 变量作为迭代器来顺序遍历列表。
步骤 1 − 要从列表中检索元素,我们可以使用以下代码来检索所有值。
//iterate the list POSITION pos = m_list.GetHeadPosition(); while (pos) { double nData = m_list.GetNext(pos); CString strVal; strVal.Format(L"%.2f\n", nData); m_strText.Append(strVal); }
步骤 2 − 这是完整的 CMFCCListDemoDlg::OnInitDialog() 函数。
BOOL CMFCCListDemoDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CList<double, double>m_list; //Add items to the list m_list.AddTail(100.75); m_list.AddTail(85.26); m_list.AddTail(95.78); m_list.AddTail(90.1); //iterate the list POSITION pos = m_list.GetHeadPosition(); while (pos) { double nData = m_list.GetNext(pos); CString strVal; strVal.Format(L"%.f\n", nData); m_strText.Append(strVal); } UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control }
步骤 3 − 当上面的代码被编译并执行时,您将看到以下输出。

在中间添加项目
要在列表中间添加项目,可以使用 CList::.InsertAfter() 和 CList::.InsertBefore() 函数。 它需要两个参数 - 首先是位置(可以添加的位置),其次是值。
步骤 1 − 让我们插入一个新项目,如以下代码所示。
BOOL CMFCCListDemoDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CList<double, double>m_list; //Add items to the list m_list.AddTail(100.75); m_list.AddTail(85.26); m_list.AddTail(95.78); m_list.AddTail(90.1); POSITION position = m_list.Find(85.26); m_list.InsertBefore(position, 200.0); m_list.InsertAfter(position, 300.0); //iterate the list POSITION pos = m_list.GetHeadPosition(); while (pos) { double nData = m_list.GetNext(pos); CString strVal; strVal.Format(L"%.2f\n", nData); m_strText.Append(strVal); } UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control }
步骤 2 − 现在您可以看到,我们首先检索了值 85.26 的位置,然后在该值之前插入了一个元素,在该值之后插入了一个元素。
步骤 3 − 当上面的代码被编译并执行时,您将看到以下输出。

更新项目值
要更新数组中间的项,可以使用 CArray::.SetAt() 函数。 它需要两个参数 - 首先是位置,第二是值。
让我们将列表中的 300.00 更新为 400,如以下代码所示。
BOOL CMFCCListDemoDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CList<double, double>m_list; //Add items to the list m_list.AddTail(100.75); m_list.AddTail(85.26); m_list.AddTail(95.78); m_list.AddTail(90.1); POSITION position = m_list.Find(85.26); m_list.InsertBefore(position, 200.0); m_list.InsertAfter(position, 300.0); position = m_list.Find(300.00); m_list.SetAt(position, 400.00); //iterate the list POSITION pos = m_list.GetHeadPosition(); while (pos) { double nData = m_list.GetNext(pos); CString strVal; strVal.Format(L"%.2f\n", nData); m_strText.Append(strVal); } UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control }
编译并执行上述代码后,您将看到以下输出。 您现在可以看到值 300.00 已更新为 400.00。

删除项目
要删除任何特定项目,您可以使用 CList::RemoveAt() 函数。 要从列表中删除所有元素,可以使用 CList::RemoveAll() 函数。
让我们删除该元素,其值为 95.78。
BOOL CMFCCListDemoDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CList<double, double>m_list; //Add items to the list m_list.AddTail(100.75); m_list.AddTail(85.26); m_list.AddTail(95.78); m_list.AddTail(90.1); POSITION position = m_list.Find(85.26); m_list.InsertBefore(position, 200.0); m_list.InsertAfter(position, 300.0); position = m_list.Find(300.00); m_list.SetAt(position, 400.00); position = m_list.Find(95.78); m_list.RemoveAt(position); //iterate the list POSITION pos = m_list.GetHeadPosition(); while (pos) { double nData = m_list.GetNext(pos); CString strVal; strVal.Format(L"%.2f\n", nData); m_strText.Append(strVal); } UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control }
编译并执行上述代码后,您将看到以下输出。 您现在可以看到值 95.78 不再是列表的一部分。
