CList的用法理解

CList是一个双向链表类。CList的优势是快速灵活的插入和删除。但是在访问元素的时候,会多一个N的时间复杂度。在元素很多的时候,建议把数据分段存储。

1、包含头文件Afxtempl.h

     在你要使用CList链表类的地方,使用#include  ,或者直接在stdafx.h中包含这句。

2、理解CList的声明和构造方法

CList的声明如下:

template< class TYPE, class ARG_TYPE >

class CList : public CObject

CList的声明有2种方式,决定的是参数的使用是引用,还是复制。

例如:

CList list1;        //注意引用符号的位置是在类型后面。<类型&>

CList list2;          

第一个参数,表示的是链表的元素的数据类型,这里类似一个声明,声明你使用的链表中的数据类型是什么。

第二个参数,分2种形式,一种是引用形式,一种是复制形式,那么这个引用和复制,体现的作用在哪里呢?其实,这个引用和复制,只是体现在元素的添加,查找上面。比如我们往刚才声明的这个链表list1中添加元素。

CList list1; //

CString str = "abc";

list1.AddTail(str);              //str是以引用的方式,添加到list1中的,类似声明一个函数 void fun(CString &a);

再看另外一个中声明方式:

CList list2;//

CString str = "abc";

list2.AddTail(str);             //str是以复制的方式添加的。

其实2种方式都能达到向链表中添加数据的目的,在数据结构很小的时候,其实是没有什么差别的,但是在数据结构很大的时候,比如一个数据元素就有1M,甚至10M,引用就变得有意义了,这个时候使用引用,链表是直接把str的地址中的内容添加到链表中了,使用复制,还需要先在内存中复制一下str,然后再把复制的内容添加到list中去。好了,现在懂了吗?如果没有,还得看下C++函数的形参的设置。是引用,还是非引用~

3、添加元素

  例如:CList  myList;

(1)在CList的尾部添加元素 

           POSITION AddTail( ARG_TYPE newElement );     //在尾部添加一个元素,返回值是新插入元素的位置

        void AddTail( CList* pNewList );                                      //在尾部添加另一个链表中的内容。链表的数据类型要一致。

          比如:myList.AddTail("abc");

  (2)  在CList的头部添加元素

          POSITION AddHead( ARG_TYPE newElement );       //在链表最开始插入一个元素,返回值是新插入的元素的位置

          void AddHead( CList* pNewList );

         例如:myList.AddHead(CString("ABC"));

 (3)在一个位置之前添加元素

          POSITION InsertBefore( POSITION position, ARG_TYPE newElement );      //在position前面插入一个元素,返回新插入元素的位置。其实就是position前面一个位置

         例如:

         POSITION pos = myList.GetHeadPostion();

         pos = myList.InsertBefore(pos, CString("ABC"));

         pos = myList.InsertBefore(pos, CString("123"));

 (4)在一个位置之后添加元素

          POSITION InsertAfter( POSITION position, ARG_TYPE newElement );       //在postion后面插入一个元素,返回新插入元素的位置

          例如:

          POSITION pos = myList.GetTailPostion();

          pos = myList.InsertAfter(pos, CString("ABC"));

          pos = myList.InsertAfter(pos, CString("123"));

4、     查找元素:CList有2个函数,是非常方便我们查找的。

       (1)直接查找元素

            POSITION Find( ARG_TYPE searchValue, POSITION startAfter = NULL) const; 返回的是查找到的元素的第一个位置(如果链表中有多个重复的元素)。没有找到就返回空

           例如:

            CList myList;

           myList.AddHead(CString("XYZ"));

           myList.AddHead(CString("ABC"));

           myList.AddHead(CString("123"));

          POSITION pos = myList.GetAt(pos));

         然后就可以通过pos来操作这个元素了。比如GetAt(pos),InsertAfter(pos)等。

         (2)通过下标来查找位置,通过下标是非常方便的。

           POSITION FindIndex( int nIndex ) const;           //返回第i个元素的位置,然后可以通过位置来对元素进行操作。

           例如:

           CList myList;

           myList.AddTail(CString("XYZ"));

           myList.AddTail(CString("ABC"));

           myList.AddTail(CString("123"));

           POSITION pos1 = myList.FindIndex(0);

           POSITION pos2 = myList.FindIndex(2);

           CString str1 = myList.GetAt(pos1);            //str1就等于"XYZ"

           CString str2 = myList.GetAt(pos2);            //str2就等于“123”

           CStirng str3 = myList.GetAt(myList.FindIndex(1));     //str3等于"ABC"

         (3)遍历查找       

//如果链表是const类型的,这些函数,返回的是一个复制元素,如果不是const的,返回的是链表中元素的引用。但是怎么设置成一个const类型的,我都还不知道。所以,一般我们使用这些函数得到的元素,都是引用的,可以直接对链表的元素复制:比如myList.GetHead() = "AAA";就能把表头置为"AAA"。

TYPE& GetHead( );                   //得到第一个元素,确保链表不为空,使用IsEmpty()

TYPE GetHead( ) const;         

TYPE& GetTail( );                     //得到表尾元素

TYPE GetTail() const;

TYPE& GetNext( POSITION& rPosition );                

TYPE GetNext( POSITION& rPosition ) const;

TYPE& GetPrev( POSITION& rPosition );

TYPE GetPrev( POSITION& rPosition ) const;

TYPE& GetAt( POSITION position );

TYPE GetAt( POSITION position ) const;

 

5、删除元素

           (1)删除全部元素,删除后,链表为空。

             void RemoveAll( );         

         例如: myList.RemoveAll();

      (2)删除position处的元素

          void RemoveAt( POSITIONposition );    //这里要保证position是有效的,不是空的,如果是空的,调试版本会报错。release版本不会报错。

         例如:myList.RemoveAt(myList.FindIndex(1));

      (3)删除表头      

          TYPE RemoveHead( );                    //返回值是没有删除的时候的表头元素。

     (4)删除表尾

         TYPE RemoveTail( );                       //返回值是没有删除的时候的表尾元素。

6、链表的遍历

          方式1:

         POSITION pos = myList.GetHeadPostion();

         while(pos != NULL)

         {

                   CString  str = myList.GetNext(pos);                 //GetNext(pos),先返回pos位置的元素的值,再把pos指向当前位置的下一个。

         }

         方式2:

         for(int i = 0 ; i < myList.GetCount(); i++)

          {

                   CString str = myList.GetAt(myList.FindIndex(i));

           }

         总结:方式2,明显比方式1慢.方式1只需要执行N此就可以了,方式2,需要执行1+2+。。。+N = (1 + N)*N/2次

由于时间关系,写的也不是非常完整,需要这方面知识的,请多看MSDN帮助信息,祝你顺利~

最后还是请教一下大家,怎么把CList声明为const类型?欢迎留言~

 

 

 

 

 

你可能感兴趣的:(CList的用法理解)