zoukankan      html  css  js  c++  java
  • vc++基础班[28]---动态数组及动态链表的讲解

    C++中也有相应的动态数组、动态链表、映射表的模板类,就是STL中的:vector、list、map
    他们属于C++标准中的一部分,对于程序的移植性来说也是不错的,但是在MFC编程中使用 CArray、CList、CMap 会更方便一些!
    CArray、CList、CMap 的由来?……
     
    ①、数组的基本说明:
    数组是固定大小的,相同数据类型的元素的顺序集合,每个元素在数组中有一个固定的位置。
    将10个数放入数组中,假设数组的名称为number,可以称数组中第一个元素为 number[0],第二个数为 number[1]……其中 0、1~9 称为元素的下标,
    下标表明元素在数组中的相对位置。
     
    例如,普通的常规静态数组定义为:
    int number[20];
    CPoint pt[10];
    CButton btn[10];
    ====================================================
    ②、MFC中的动态数组类是:CArray
    CArray 是一个模板类,类似于常规数组,但是长度可动态增长;
    常规数组在使用前必须先知道元素的个数,即先确定大小,而MFC的动态数组类 CArray 创建的对象可以根据需要动态地增大或减小,
    数组的起始下标是0,而上限可以是固定的,也可以随着元素的增加而增加,数组在内存中的位置仍然是连续的(这一点很关键)!
     
    虽然 CArray 是一个模板类,但是微软在 MFC 中针对各种常用的变量类型分别定义了:
    CByteArray、CDWordArray、CObArray、CPtrArray、CStringArray、CUIntArray、CWordrray 等,
    所以,如果大家在程序中使用的数据结构有合适以上几种的类型的,可以直接拿过来用,无需重复定义,详见MSDN!
    ========================================================
    ③、CArray 类型对象的定义:其中带有 ARG_ 前缀的是传入类型,另外一个则是返回类型
    CArray <int, int> arrInt;
    CArray <CPoint, CPoint &> arrPoint;
    CArray <CButton, CButton &> arrButton;
    //在使用基本类型的时候,第二个参数可以不用传引用,但是使用类类型等符合类型的时候第二个参数最好传递对象的引用,
    //这样可以避免拷贝构造函数的调用,提高效率!
     
    CStringArray arrString;
    CByteArray arrByte;
    ====================================================
    ④、CArray 类的使用:
    // 插入节点、删除节点、遍历数组
    INT_PTR idx = 0;
    CArray <CPoint, CPoint &> arrPoint;
    //arrPoint.SetSize(100, 10);
    BOOL bRet = arrPoint.IsEmpty();
    for (idx = 0; idx < 100; ++idx){
     CPoint pt;
     pt.SetPoint(idx, idx);
     arrPoint.Add(pt);//元素的添加
    }
    int nCount = arrPoint.GetCount();
    int maxIdx = arrPoint.GetUpperBound();
    bRet = arrPoint.IsEmpty();
    CPoint point = arrPoint.GetAt(10);
    arrPoint.RemoveAt(10, 5); //指定元素的删除
    nCount = arrPoint.GetCount();
    point = arrPoint.GetAt(10);
    point = arrPoint[11];
     
    //数组的遍历
    for (idx = 0; idx < arrPoint.GetCount(); ++idx){
     CPoint pt = arrPoint.GetAt(idx);
     pt.x = 123;
    }
     
    point.x = point.y = 999;
    arrPoint.SetAt(5, point);
     
    for (idx = 0; idx < arrPoint.GetCount(); ++idx){
     CPoint pt = arrPoint.GetAt(idx);
     pt = pt;
    }
     
    arrPoint.RemoveAll();
    nCount = arrPoint.GetCount();
    bRet = arrPoint.IsEmpty();
    ====================================================
    ⑤、CArray 的效率问题:
    问:CArray 确实很好用,但是为什么到了10万个数据以后,赋值的速度就很慢了呢?
    答:CArray 是很好用的,只是因为你没有指定数组的最大尺寸。
    因此,当你添加新元素时,该类会从堆中重新分配空间,不幸的是,该类会在每次插入新元素时都为数组重新分配空间,
    如果你向它添加了很多新元素,所有这些分配和复制数组的操作会就会使它变慢。
     
    解决该问题的方法是,你可以使用SetSize函数的第二个参数来改变这种重新分配的频率。
    例如,如果你把该参数设置为500,则每次数组空间超出时它才重新分配并添加500个新空间,而不是1个,
    这样一来,你就可以不用重新分配而添加了另外499个元素空间,这也会大大提高程序的运行速度。
     
    ====================================================
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ====================================================
    ⑥、链表的基本说明:
    链表也是一个有序数据的集合,但每个元素包含下一个元素的地址。
    每个元素包含两部分:数据和链(链是存储下一个元素地址的指针)
    此处只讨论单链表,每个节点仅有一个指向后继节点的链。通常使用一个指针变量指向第一个元素,称为链表的头指针。链表的最后一个元素包含一个空指针,标识链表的结束。
    链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表
     
    链表在内存中的位置是不连续的(这一点很关键)!
     
    例如,普通的链表节点定义为:
    struct node
    {
        int num;
        struct node *p;
    } ;
    ====================================================
    ⑦、MFC中的动态链表类是:CList
    CList 是双向链接表,因此 头、尾和表中已知位置(POSITION)的元素插入速度很快。
    按值或者索引查找需要顺序搜索,然而如果表很长则速度可能慢!
     
    虽然 CArray 是一个模板类,但是微软在 MFC 中针对各种常用的变量类型分别定义了:
    CPtrList、CObList、CStringList 等,
    所以,如果大家在程序中使用的数据结构有合适以上几种的类型的,可以直接拿过来用,无需重复定义,详见MSDN!
    ====================================================
    ⑧、CList 类型对象的定义:其中带有 ARG_ 前缀的是传入类型,另外一个则是返回类型
    CList <int, int> arrInt;
    CList <CPoint, CPoint &> arrPoint;
    CList <CButton, CButton &> arrButton;
    //在使用基本类型的时候,第二个参数可以不用传引用,但是使用类类型等符合类型的时候第二个参数最好传递对象的引用,
    //这样可以避免拷贝构造函数的调用,提高效率!
    ====================================================
    ⑨、CList 类的使用:
    int idx = 0;
    CList <CPoint, CPoint &> ptList(100);
    BOOL bRet = ptList.IsEmpty();
    for (idx = 0; idx < 100; ++idx){
     CPoint pt;
     pt.SetPoint(idx, idx);
     ptList.AddTail(pt);//向链表结尾添加元素
    }
    int nCount = ptList.GetCount();
    bRet = ptList.IsEmpty();
     
    //POSITION ps = 10;
    CPoint point = ptList.GetAt(ptList.FindIndex(10));
    ptList.RemoveAt(ptList.FindIndex(10)); //指定元素的删除
    nCount = ptList.GetCount();
    point = ptList.GetAt(ptList.FindIndex(10));
     
    //链表的遍历
    POSITION pos = ptList.GetHeadPosition();
    for (idx = 0; idx < ptList.GetCount(); ++idx) {
     CPoint pt = ptList.GetNext(pos);
     pt.x = 123;
    }
     
    point.x = point.y = 999;
    ptList.SetAt(ptList.FindIndex(5), point);
     
    pos = ptList.GetHeadPosition();
    for (idx = 0; idx < ptList.GetCount(); ++idx) {
     CPoint pt = ptList.GetNext(pos);
     pt = pt;
    }
     
    ptList.RemoveAll();
    nCount = ptList.GetCount();
    bRet = ptList.IsEmpty();
     
    ⑩、※※※ 链表与数组的区别 ※※※
       数组是将元素在内存中连续存放,由于每个元素占用内存相同,所以可以通过下标迅速访问数组中任何元素。
    但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。
    同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。
     
       链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。如:上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。
    如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了, 只要修改元素中的指针就可以了。
     
       ※※※ 从上面的比较可以看出,如果需要快速访问数据,很少或不插入和删除元素,就应该用数组,相反, 如果需要经常插入和删除元素就需要用链表了!
     
    ====================================================
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ====================================================
     
    11、映射表的基本说明:
    映射表类 也称作为“字典”,就像一种只有两列的表格,一列是关键字,一列是数据项,它们是一一对应的,是以键值对的形式出现的!
    关键字是唯一的(※ 这点很重要),给出一个关键字,映射表会很快找到对应的数据项。
    映射表的查找是以哈希表的方式进行的,因此在映射表中查找数值项的速度很快。
    映射类最适用于需要根据关键字进行快速检索的场合。
     
    例如:公司的所有职员都有一个工号和自己的姓名,工号就是关键字,给出一个工号,就可以很快的找到相应的姓名!
    姓名可以重复,或者说有同名的情况,但是工号一定不能出现重复的!
     
    12、MFC中的动态映射表类是:CMap
     
    虽然 CMap 是一个模板类,但是微软在 MFC 中针对各种常用的变量类型分别定义了:
    CMapWordToPtr、CMapPtrToWord、CMapPtrToPtr、CMapWordToOb、CMapStringToPtr、CMapStringToOb、CMapStringToString 等,
    所以,如果大家在程序中使用的数据结构有合适以上几种的类型的,可以直接拿过来用,无需重复定义,详见MSDN!
     
    13、CMap 类型对象的定义:其中带有 ARG_ 前缀的是传入类型,另外一个则是返回类型
    CMap <int, int, CString, LPCTSTR> intMapString;
    CMap <int, int, int, int> intMapInt;
    CMap <int, int, CPoint, CPoint &> intMapPoint;
    CMap <long, long, CButton, CButton &> longMapButton;
    CMap <CString, LPCTSTR, int, int> strMapString;
    //在使用基本类型的时候,第二、四个参数可以不用传引用,但是使用类类型等符合类型的时候第二、四个参数最好传递对象的引用,
    //这样可以避免拷贝构造函数的调用,提高效率!
     
    14、CMap 类的使用:
    CMap<int, int, CString, LPCTSTR> intMapString(20);
     
    CString strText;
    for (int idx = 0; idx < 20; ++idx){
     strText.Format(_T("%s%d"), _T("The number is : "), idx);
     intMapString.SetAt(idx, strText);
    }
     
    int nCount = intMapString.GetCount();
    BOOL bRet = intMapString.IsEmpty();
     
    strText.Empty();
    intMapString.Lookup(10, strText);//根据key查找元素
    intMapString.RemoveKey(10); //根据key删除元素
    nCount = intMapString.GetCount();
     
    strText.Empty();
    intMapString.Lookup(10, strText); //还能找到吗?
     
    //映射表的遍历
    int nKey = 0;
    POSITION pos = intMapString.GetStartPosition();
    while (pos != NULL) {
     strText.Empty();
     intMapString.GetNextAssoc(pos, nKey, strText);
    }
     
    intMapString.SetAt(5, _T("abcdefg123"));
     
    intMapString.RemoveAll();
    nCount = intMapString.GetCount();
    bRet = intMapString.IsEmpty();
     
     
    ★ 课后作业:
    1、练习使用 CStringArray 等类的使用;
    ------------------------------------- End -------------------------------------------
  • 相关阅读:
    单源最短路——SPFA算法(Bellman-Ford算法队列优化)
    A Compatible Pair
    欧拉函数知识点总结及欧拉函数打表代码(数论)
    Fafa and the Gates(模拟)
    C语言--链表基础模板
    路由器如何设置上网(TP-LINK)
    学员成绩管理系统
    Bad Cowtractors(最大生成树)
    Agri-Net(最小生成树)
    Median Weight Bead(最短路—floyed传递闭包)
  • 原文地址:https://www.cnblogs.com/liaocheng/p/4243376.html
Copyright © 2011-2022 走看看